参考:
[1] https://blog.csdn.net/lyj1597374034/article/details/106720629
[2] https://www.cnblogs.com/hy87/p/5982280.html
DualPivotQuicksort源码解析
以jdk1.8为例,DualPivotQuicksort主要用于7中基本类型的排序。本文以int类型为例,介绍排序的主要流程以及所用的排序算法。
- 当排序的个数小于47时,从最左边开始时,使用普通的插入排序。如果不是最左边,可以使用优化后的双数插入排序。
- 当大于47,小于286时,使用快速排序,选取5个基准点,判断选取单枢快速排序还是双枢快速排序。
- 大于286,使用timSort排序的思想。使用run数组寻找升序或降序序列。如果run数组的个数大于67,则认为它是顺序很乱的数组,直接使用快速排序。否则直接进行合并。
- 具体流程如下:
/**
* If the length of an array to be sorted is less than this
* constant, Quicksort is used in preference to merge sort.
*/
/**
如果排序的数组长度小于286,优先使用quicksort排序
*/
private static final int QUICKSORT_THRESHOLD = 286;
// Use Quicksort on small arrays
if (right - left < QUICKSORT_THRESHOLD) {
sort(a, left, right, true);
return;
}
1 插入排序
首先解释下leftmost参数,这个参数的意义就是排序的值是否在数组的最左边,如果在最左边,则使用传统的插入排序,如果不是,则使用优化后的双数插入排序。
首先判断数组长度。小于47时,根据leftmost判断,选择合适的插入排序。
1.1 传统插入排序
每次从无序中选取一个值插入到有序的部分。
for (int i = left, j = i; i < right; j = ++i) {
int ai = a[i + 1];//保存当前元素值
while (ai < a[j]) {
//插入到有序序列中
a[j + 1] = a[j];
if (j-- == left) {
break;
}
}
a[j + 1] = ai;
}
1.2 双数插入排序
/*
* Skip the longest ascending sequence.
跳过前面最长的升序序列
*/
do {
if (left >= right) {
return;
}
} while (a[++left] >= a[left - 1]);
/*
* Every element from adjoining part plays the role
* of sentinel, therefore this allows us to avoid the
* left range check on each iteration. Moreover, we use
* the more optimized algorithm, so called pair insertion
* sort, which is faster (in the context of Quicksort)
* than traditional implementation of insertion sort.
相邻元素扮演者岗哨的角色,这样就可以减少比较的次数。
选取2个值,并先插入最大值,那么最小值只需要和最大值的左边开始比较,而不需要比较右边的值。
*/
for (int k = left; ++left <= right; k = ++left) {
int a1 = a[k], a2 = a[left];
if (a1 < a2) {
//找到最大值a1
a2 = a1; a1 = a[left];
}
while (a1 < a[--k]) {
//先插入a1
a[k + 2] = a[k];
}
a[++k + 1] = a1;
while (a2 < a[--k]) {
//再插入a2
a[k + 1] = a[k];
}
a[k + 1] = a2;
}
//当k=++left=right时,++left就会大于right,此时最后一个元素并没有排序,需要处理
int last = a[right];
while (last < a[--right]) {
a[right + 1] = a[right];
}
a[right + 1] = last;
}
2 快速排序
大于47时,使用快速排序。
- 先均匀找到5个基准元素,判断是否相等。
- 如果都不相等,使用双枢快速排序。
- 有相等的时候,选取单枢快速排序。
具体过程都在源码中进行注释
/**
* If the length of an array to be sorted is less than this
* constant, insertion sort is used in preference to Quicksort.
如果数组长度小于47,优先使用插入排序,而不是快速排序
*/
private static final int INSERTION_SORT_THRESHOLD = 47;
-
// leftmost判断是否在左区间 private static void sort(int[] a, int left, int right, boolean leftmost) { int length = right - left + 1; // 判断数组长度 如果小于47 使用插入排序 // Use insertion sort on tiny arrays if (length < INSERTION_SORT_THRESHOLD) { if (leftmost) { //如果是左区间,使用传统的插入 /* * Traditional (without sentinel) insertion sort, * optimized for server VM, is used in case of * the leftmost part. */ for (int i = left, j = i; i < right; j = ++i) { int ai = a[i + 1]; while (ai < a[j]) { a[j + 1] = a[j]; if (j-- == left) { break; } } a[j + 1] = ai; } } else { //不是在左区间的情况下 /* * Skip the longest ascending sequence. */ //跳过最左边的升序 do { if (left >= right)