昨天学习了快速排序,回顾一下,快速排序的做法就是一次排序将一个数放到正确的位置上,并返回当前位置的索引,然后避开此位置,对其他位置进行重复的排序,有点像前边学到的归并排序,不知道大家有没有印象。
归并排序和快速排序的思想都是递归分割,然后对分割出来的区域进行排序,但是有一个不同的地方就是,归并排序每次分割都会平均分成二等分,但是快速排序却十分的不稳定,最理想的情况就是能和归并排序一样,找到一个中间数字,但是试想,如果数组是排好序的,而我们如果还是以第一个元素作为参考值,那么每次都需要遍历整个数组,那么这时候快速排序就退化到了O(n²)级别的算法了
为了防止这种情况发生,我们不再使用第一个元素作为参照,而是适合用一个随机生成的数字作为参照数的下标,这样就防止了上述情况的发生。
并且采用双头共进的方式进行优化
所谓的双头共进,就是分别创建两个索引,从两端开始进行遍历。左边的索引寻找比参照数大的元素,右边的索引寻找比参照数小的元素,找到之后交换位置,然后继续重复上述操作,直至到达我们设置的边界,这样又进一步提高了效率
废话不多说,直接上代码
package com.smarking.lzy.part1;
/*
* 随机双向快排
*
*
*
* */
public class QuitSortRandom {
public static void sort(int [] arr,int left,int right) {
// if(right - left < 15) {
//
// }
if(left >= right) {
return;
}
int p = partititon(arr,left,right);
sort(arr,left,p-1);
sort(arr,p+1,right);
}
private static int partititon(int [] arr,int left,int right) {
int index = (int) (Math.random() * (right - left + 1)+left);
SortTestHelper.swap(arr, left, index);
int value = arr[left];
int i = left + 1;
int j = right;
while(true) {
while(i <= right && arr[i] < value) {
i++;
}
while(j >= left + 1 && arr[j] > value) {
j--;
}
if(i > j) {
break;
}
SortTestHelper.swap(arr, i, j);
i++;
j--;
}
SortTestHelper.swap(arr, left, j);
return j;
}
public static void main(String[] args) {
int testTime = 1;
int maxValue = 100;
int maxSize = 5;
boolean success = true ;
for(int i = 0;i < testTime;i++) {
//int [] arr1 = SortTestHelper.generateRandomArray(maxSize, maxValue);
int [] arr1 = {-43 ,90 ,9 ,-4 ,3,4 };
int [] arr2 = SortTestHelper.copyArray(arr1);
sort(arr1,0,arr1.length-1);
SortTestHelper.comparator(arr2);
if(!SortTestHelper.isEqual(arr1, arr2)) {
success = false;
SortTestHelper.printArray(arr1);
SortTestHelper.printArray(arr2);
break;
}
}
if(success) {
System.out.println("Nice!!!");
}else {
System.out.println("Fuck!");
}
}
}