快速排序的总结和优化
-
基础快排
快排的基本框架就是下边这样。更鲁棒一点的话,还需要考虑传入的array是否是非法参数。
此处优化:应当将数组,打乱顺序,如果数组基本有序,快排的时间复杂度将退化到
应该在传入sort之前就将数组 shuffle。
public static void sort(int[] array,int lo ,int hi){ if (array == null || lo < 0 || hi > array.length - 1) { throw new IllegalArgumentException("Invalid Parameters"); } if(lo>=hi){ return ; } int index=partition(array,lo,hi); sort(array,lo,index-1); sort(array,index+1,hi); }
shuffle
public static void shuffle(int a[]){ int n = a.length; for (int i = n; i > 0 ; i--) { int index =(int)(Math.random()*i); swap(a,index, i-1); } }
完整测试快排过程
public static void main(String[] args) { int a[] = {1,2,3,4,5,6,7,8}; int len = a.length; shuffle(a); sort(a,0,len-1); for (int i = 0; i < len; i++) { System.out.println(a[i]); } }
-
重点是 partition
《算法》第四版给的partition如下:
存在问题,当数字仅有一个数字的时候,a[++i]越界了。并不鲁棒,所以使用这个之前需要单独处理数组只有一个数字的测试。
public static int partition(int []a,int lo,int hi){ int i = lo; int j = hi + 1; while(true){ // 若一趟有序则 退出 while(a[++i] < a[lo]) if (i == hi) break; while(a[--j] > a[lo]) if( j == lo) break; if (i >= j) break; swap(a,i,j); } swap(a,lo,j); return j; }
较为鲁棒的写法(而且不使用swap 进行交换)
public static int partition(int []a,int lo,int hi){ int key=a[lo]; while(lo<hi){ while(array[hi]>=key&&hi>lo){ hi--; } array[lo]=array[hi]; while(array[lo]<=key&&hi>lo){ lo++; } array[hi]=array[lo]; } array[hi]=key; return hi; }
上面方法避免了数组仅有一个数字的时候的越界问题,但是不够优化,因为我们默认选lo 作为我们的枢值,然后进行划分的。
进一步优化的方法是,枢值的选取应该也是随机的。这个随机是在lo~hi之间随机选一个来进行。
public static int partition(int []a,int lo,int hi){ // math.random 返回[0.0,1.0)的double 值 int index = lo + (int)(Math.random()*(hi-lo+1)); swap(a,lo,index); int key = a[lo]; while(lo < hi ){ while(a[hi] > key && hi > lo){ hi--; } a[lo] = a[hi]; while(a[lo] < key && hi > lo){ lo++; } a[hi] = a[lo]; } a[hi] = key; return hi; }
最优化的方法是 :三数取中间的数 来当 基准点
public int partition(int a[],int lo,int hi){ int mid = lo+(hi-lo)>>1; // 让mid 是 介于 a[hi] 和 a[lo] 之间的数 if (a[mid] > a[hi]) swap(a,mid,hi); if(a[mid] < a[lo]) swap(a,mid,lo); // 此时确保a[lo] < a[mid] < a[hi] 再将mid交换给 lo // 此时lo 为 lo mid hi 中的 中值 if (a[mid] > a[lo]) swap(a,mid,lo); int key = a[lo]; while(lo < hi){ while(a[hi] > key && hi > lo ) hi--; a[lo] = a[hi]; while(a[lo] < key && hi > lo) lo++; a[hi] = a[lo]; } a[hi] = key; return hi; }
网友评论