从前天开始,学习了快速排序,快速排序是一门很优秀也经常会被用到的排序,所以昨天我们学习了快速排序的进阶版本,双路快排,但是除此之外,还能进行再度的优化,这就是我们今天要学习的,三路快排
What?三路?刚刚昨天学习了双路,怎么又蹦出个三路来了?这到底有多少路?
说实在话,昨天我学到这个的时候也是懵逼的,但是经过学习之后,我发现,其实三路和双路都是差不多的,双路排序是两个索引,那么显而易见,三路排序就是三个索引啦
下面我们来总结一下基础版,双路版,三路版的区别:
基础版:将数组分成小于和大于等于两个区间
双路版:将数组分成小于等于和大于等于两个区间
三路版:将数组分成小于,等于,大于三个区间
可以看出,三路版对于区间的划分更加的精细,那么如何去实现它呢?其实就是在双路版的基础上再加上一个索引
lt: 要保证在[ left , lt - 1] 这个区间上的元素都是小于value的
gt: 要保证在[ gt , right ] 这个区间上的元素都是大于value的
i: 就是我们当前所需要校验的位置
一定要注意边界问题,别问我为什么,血的教训,要注意区间两端的开闭
废话不多说,直接上代码:
package com.smarking.lzy.part1;
/*
* 三路快速排序
*
* 双路排序是两个索引,所以三路排序就是三个索引了
* 单路和双路排序都是将区间划分成两个区域:小于(等于)参考值,大于(等于)参考值
* 三路排序最终的结果就是将区间划分成三个区域:小于参考值,等于参考值,大于参考值
*
* 所以我们这次返回的就是等于参考值的区间,我们返回一个数组,数组中存储两个元素,一个是等于我们参考值的区间的左边界,另外一个是右边界
* arr[left + 1 ... lt] < value
* arr[gt ... right] > value
* arr[lt+1 ... i) == value
*
* 边界很重要!!!问题出错都是处在边界的理解,一定要好好理解边界问题!
* */
public class QuitSortThird {
public static void sort(int [] arr ,int left ,int right) {
//设置递归的出口
if(left >= right) {
return;
}
int [] positions = partition(arr,left,right);
sort(arr,left,positions[0] - 1);
sort(arr,positions[1],right);
}
//重点,返回等于参考值的区间
private static int [] partition(int [] arr,int left,int right) {
//创建一个数组,用来存储区间的左右边界,默认第一个存左边界,第二个存有边界
int [] positions = new int[2];
//随机选择一个位置作为参照值
int index = (int) (Math.random() * (right - left + 1)+left);
//int index = 6;
SortTestHelper.swap(arr, left, index);
int value = arr[left];
//定义三个索引,分别是左边界,有边界和用来遍历的索引
int i = left + 1;//用来遍历整个数组的索引
int lt = left;//左边界
int gt = right + 1;//右边界
while(i < gt) {
if(arr[i] < value) {
SortTestHelper.swap(arr, i, lt + 1);
i++;
lt++;
}else if(arr[i] > value) {
SortTestHelper.swap(arr, i, gt - 1);
gt--;
//i++;这个地方不能自增,因为右边的元素都是没有进行遍历的,如果自增,就会跳过该元素
}else {
i++;
}
}
SortTestHelper.swap(arr, left, lt);
positions[0] = lt;
positions[1] = gt;
return positions;
}
public static void main(String[] args) {
int testTime = 10000;
int maxValue = 100;
int maxSize = 10000;
boolean success = true ;
for(int i = 0;i < testTime;i++) {
int [] arr1 = SortTestHelper.generateRandomArray(maxSize, maxValue);
//int [] arr1 = {1 ,2 ,-1, 5 ,-2, 4, 2, 5 };
int [] arr2 = SortTestHelper.copyArray(arr1);
int [] arr3 = SortTestHelper.copyArray(arr1);
sort(arr1,0,arr1.length-1);
SortTestHelper.comparator(arr2);
if(!SortTestHelper.isEqual(arr1, arr2)) {
success = false;
SortTestHelper.printArray(arr3);
SortTestHelper.printArray(arr1);
break;
}
}
if(success) {
System.out.println("Nice!!!");
}else {
System.out.println("Fuck!");
}
}
}
这两天就不学习新的算法了,先停下来巩固一下之前学的
这两天我会对之前的算法进行一个对比,然后我会尝试把这些算法结合在一起,使得他们的效率做到极致。
算法是一种长远的投资,我相信,肯定会有量变到质变的一天!