快速排序可能是应用最广泛的排序算法了,它的实现简单,只需要一个很小的辅助栈,将长度为N的数组排序所需时间和NlogN成正比,在本篇文章讲述一下改进的快速排序-三路快排
三路快排
所谓三路快排,一言以蔽之,就是同时排序小于选定值,等于选定值和大于选定值三种情况
在这里我们随机选取一个值v作为分界点,分别排序小于v,等于v和大于v的,这里之所以随机选取是考虑到如果我们选取数组第一个值,那么在一个完全有序的数组里,我们的快速排序就会退化为log(n^2)
先来看代码:
package vip.lanco; import java.util.*; public class QuickSort3 { // 我们的算法类不允许产生任何实例 private QuickSort3(){} // 递归使用快速排序,对arr[left...right]的范围进行排序 private static void sort(Comparable[] arr, int left, int right){ // 对于小规模数组, 使用插入排序会更加快速 if( right <left ){ //自己实现插入排序 } /* 随机在arr[l...r]的范围中, 选择一个数值作为标定点pivot*/ swap( arr, left, (int)(Math.random()*(right-left+1)) + left ); Comparable v = arr[left]; //设置边界值 int lt = left; // arr[left+1...lt] < v int gt = right + 1; // arr[gt...right] > v int i = left+1; // arr[lt+1...i) == v while( i < gt ){ if( arr[i].compareTo(v) < 0 ){ swap( arr, i, lt+1); i ++; lt ++; } else if( arr[i].compareTo(v) > 0 ){ swap( arr, i, gt-1); gt --; } else{ // arr[i] == v i ++; } } swap( arr, left, lt ); sort(arr, left, lt-1); sort(arr, gt, right); } public static void sort(Comparable[] arr){ int n = arr.length; sort(arr, 0, n-1); } //两值交换 private static void swap(Object[] arr, int i, int j) { Object t = arr[i]; arr[i] = arr[j]; arr[j] = t; } //输出显示 private static void show(Comparable[] a) { for (int i = 0; i < a.length; i++) { System.out.print(a[i]+"--"); } } // 测试 QuickSort3 public static void main(String[] args) { Comparable[] arr = new Comparable[] {23,45,1,21,67,78,89,55,12,34,22,11,5,6,9}; sort(arr); show(arr); return; } }
如上,我们以数组[23,45,1,21,67,78,89,55,12,34,22,11,5,6,9]为例
一开始设置的边界值lt=0,gt=15,i=1,假设随机选取pivot标志后为5;
则arr[1]=45 > v=5 所以交换45和9的位置,同时gt-1,此时arr[1]=9;
接着继续判断arr[1]=9 > v=5 ,所以这时候交换6和9的位置 ,此时arr[1]=6
如此下去直到最后只剩下:
v(left) | <v(lt) | ==v(gt,i) | >v(right) |
再去交换left和lt的值。
小改进,在right-left<=15左右时候,我们可以改为插入排序,效率会有所改进