Arrays.sort底层排序算法
一直以来,我都认为Java内部排序的算法是快速排序。直到有一天,我在面经上看到了有一道这样子的问题。我才发觉,事情远没有我想的那么简单。
底层排序算法又根据目标数组分为了好几种排序方法。
- 归并排序为非递归写法(应该是为了避免递归次数过多引起的堆栈溢出)
- 快排又分为两种,双基准和三路快排
int、long类型
点进我们的底层源码来,我们就会看到一行注释,说的就是在小数组的情况下,使用快速排序。
// Use Quicksort on small arrays
if (right - left < QUICKSORT_THRESHOLD) {
sort(a, left, right, true);
return;
}
但是!我们在点进这个sort后,就又又又会发现又有一行注释,说的是在微小数组里,使用插入排序。
// Use insertion sort on tiny arrays
if (length < INSERTION_SORT_THRESHOLD) {
if (leftmost) {
那么两种数组是根据多大的长度来区分的呢
数组长度小于int QUICKSORT_THRESHOLD = 286
286这个阈值时,且大于int INSERTION_SORT_THRESHOLD = 47
47是,采用的就是快速排序了,小于47就采用插入排序。
当然了,这两个排序就不想多说了,大家应该也都非常清楚了。
重点讲一下大于286时,是采用哪一种排序呢?
长度大于286后,就会采用归并排序了。
可是在采用归并排序之前,底层还是会遍历整个数组,为接下来的排序做好准备。
/*
* Index run[i] is the start of i-th run
* (ascending or descending sequence).
*/
int[] run = new int[MAX_RUN_COUNT + 1];
int count = 0; run[0] = left;
// Check if the array is nearly sorted
for (int k = left; k < right; run[count] = k) {
if (a[k] < a[k + 1]) { // ascending
while (++k <= right && a[k - 1] <= a[k]);
} else if (a[k] > a[k + 1]) { // descending
while (++k <= right && a[k - 1] >= a[k]);
for (int lo = run[count] - 1, hi = k; ++lo < --hi; ) {
int t = a[lo]; a[lo] = a[hi]; a[hi] = t;
}
} else { // equal
for (int m = MAX_RUN_LENGTH; ++k <= right && a[k - 1] == a[k]; ) {
if (--m == 0) {
sort(a, left, right, true);
return;
}
}
}
/*
* The array is not highly structured,
* use Quicksort instead of merge sort.
*/
if (++count == MAX_RUN_COUNT) {
sort(a, left, right, true);
return;
}
}
上面的逻辑主要就是,在遍历整个数组的同时,将一段无序的数组给排序,同时将一个标志的值给+1。要是这个值在遍历数组的过程中超出int MAX_RUN_COUNT = 67
的话,就代表着整个数组是高度无序的,更加适合快排,否则就进行最终的归并排序了。