上面提到了最常规的排序,排序,然而在面对完全有序的数组时,快速排序的效率明显降低到了O(n^2)。快速排序划分的子数组越不平衡,快排就会降低。
快速排序采用的是分而治之的思想,如果数组完全有序的话,快排分层级提升到了n,而每次都要与所有的元素进行对比。因此在面对完全有序元素时,可对快速排序进行如下优化:
随机寻找下标,不直接从最左边开始寻找。
private static int partition(int[] arr, int l, int r) {
//原本默认从最左边开始
//新增下面一行,这回每次partion一般不会从最左边开始,划分的次数也不会降低到n
swap(arr,l, new Random().nextInt((r-l)) + l );
int v = arr[l];
int j = l;
for (int i = l + 1; i 定义两个下标
i 的位置向后扫描到(e = arr[i]) >= v,然后i停止
然后j往前扫描,直到arr[j] 

当出现大量重复元素的时候,重复的元素也会分配在橙色区域和紫色区域,这样划分的区域就不会特别偏向某一方。
实现:
public static void sort(int[] arr){
sort(arr,0,arr.length - 1);
}
private static void sort(int[] arr, int l, int r) {
if (l >= r){
return;
}
int p = partition2(arr,l,r);
sort(arr,l,p);
sort(arr,p + 1,r);
}
private static int partition2(int[] arr, int l, int r) {
Hepler.swap (arr,l,new Random().nextInt((r-l)) + l);
int i = l + 1;
int j = r;
int v = arr[l];
log.info("当前比较的v = {}",v);
while (true){
while (i = l && arr[j] > v){
j--;
}
if (i > j){
break;
}
log.info("交换前数组:{}",arr);
Hepler.swap(arr,i,j);
log.info("找到的i = {},j={}",i,j);
log.info("交换后数组:{}",arr);
i++;
j--;
}
Hepler.swap(arr,l,j);
log.info("一次partion的数组:{}",arr);
return j;
}
之前排序都是将元素分为小于v,大于v。而三路快速排序,则将元素划分为:
流程:
定义3个会移动的索引,lt,i,gt, i指向当前要比较的元素

当arr[i] > v的时候,只需要把arr[i]和arr[gt - 1]的元素交换位置,但是i的位置不用变,gt的元素向前移动一个元素。
实现:
public static void sort(int[] arr){
quickSortThreeWays(arr,0,arr.length - 1);
}
private static void quickSortThreeWays(int[] arr, int l, int r){
if (r v
//数组中最后一个元素
int gt = r + 1;
// arr[lt + 1...i] == v
//第一个元素开始
int i = l + 1;
while (true){
if (arr[i] == v){
i++;
}else if (arr[i] v){
Hepler.swap(arr,i,gt - 1);
gt--;
}
log.info("当前i={} , lt = {},gt = {}",i,lt,gt);
log.info("当前数组{}",arr);
if (i >= gt){
break;
}
}
Hepler.swap(arr,l,lt );
log.info("一次quickSort数组{}",arr);
quickSortThreeWays(arr,l,lt - 1);
quickSortThreeWays(arr,gt,r);
} 在《剑指Offer》上看到一句话,查找相对而言较为交单,不外乎顺序查找,二分查找,哈希查找和二叉树排序查找,在面试的时候不管使用循环还是递归,面试官都期待应聘者能信手沾来的写出完整的二分查找代码,否则连继续面试的兴趣都没有。
排序是算法中的基础,加油。
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/3518/viewspace-2809796/ ,如需转载,请注明出处,否则将追究法律责任。