在之前的博客里说了快排的基本原理,并配图和代码说明了执行流程(https://www.cnblogs.com/bruceChan0018/p/15209130.html)。在快排的优化手段里,也提到了JDK1.8中的Arrays.sort用到了双轴快排。这里就主要说明双轴快排的流程,原理和代码实现。
这次在网上找到了比较好的图解说明,这里就不自己画图了,原文的讲解也是很好的,这里给出【参考】链接:https://www.cnblogs.com/bigsai/p/13930945.html
首先结合图说明流程:
1.我们的目标:
选定了第一个元素和最后一个元素作为双轴之后,最终的目标是化为左侧子序列为小于pivot1的,右侧是大于pivot2的,中间则是介于二者之间的。由于这个过程与位置、大小都有关系,所以双轴右侧一定要比左侧大,如果不同,那么先进行左右元素的交换,保证左比右小。
2.整个过程,需要从start+1位置的元素开始处理,一直处理到end-1的位置,由自由滑动的K进行遍历。在比较的过程中,整个区间被分为了四个部分:比左轴等小的;比右轴等大的;小于左轴大于右轴的;未处理的。这四个部分分别由left,k,right三个位置标记隔开:
3.初始的状态,left=start; right=end; k=left+1。当arr[k]<=arr[left]时,left坐标先右移1个,然后和k位置值交换,交换后k右移,此时left的区间就往后扩大一位。注意如果是k=left+1的位置发生交换,那就相当于k位置的元素自我交换,可以优化掉。
4.如果arr[k]>=arr[right],那么对于right坐标先进行左移,而后和k位置元素进行交换。此时要特别注意,由于k位置的元素发生了变化,那么k就不能右移了,而应该进入下一轮比较的循环中。
5.在arr[k]的值,介于左右两侧之间时,left和right的位置都不动,k++,并进入下一轮循环的比较。留下来的元素就是位于二者之间的。
6.当k将所有的元素都遍历完,还要处理最后一步:将start和end两个位置的元素放到left与right位置。此时整个区间的状态如下图:
7.从图中可以很清楚的看到下一轮的几个排序应该如何界定边界了。
代码如下:
public class DualPivotQuickSort { public static void dualQuicksort(int[] array, int start, int end) { if (array == null || array.length < 2) { return; } if (end < start) { //如果放入的初始位置有错误,此时抛异常提示; //如果是循环过程中造成的初始位置比结尾位置大,那么要在程序中避免 throw new IllegalArgumentException("param error!"); } //默认从小到大排序 //保证左边节点比右边节点要小 if (array[start] > array[end]) { Common.swampValue(array, start, end); } int left = start; int right = end; int k = start + 1; int pivot1 = array[start]; int pivot2 = array[end]; while (k < right) { if (array[k] <= pivot1) { if (left + 1 == k) { //避免left就在k前面时进行元素的自我比较交换 ++left; } else { Common.swampValue(array, ++left, k); } k++; } else if (array[k] >= pivot2) { //由于放入了一个新的元素进来,此时的k位置要继续与左侧比较 Common.swampValue(array, --right, k); } else { k++; } } if (left != start) { //相等说明这边没有元素发生变化,所有元素都比它大,不用交换位置 Common.swampValue(array, start, left); } if (right != end) { Common.swampValue(array, end, right); } if (start < left - 1) { dualQuicksort(array, start, left - 1); } if (left + 1 < right - 1) { dualQuicksort(array, left + 1, right - 1); } if (right + 1 < end) { dualQuicksort(array, right + 1, end); } } public static void main(String[] args) { int[] range = {12, 13, 22, 31, 1, 3, 4, 5, 6, 7, 8, 323, 423}; dualQuicksort(range, 0, range.length - 1); System.out.println("Arrays.toString(range) = " + Arrays.toString(range)); } }