一直以来,我都认为Java内部排序的算法是快速排序。直到有一天,我在面经上看到了有一道这样子的问题,我才发觉,事情远没有我想的那么简单。
在JDK1.8中,自带的底层排序算法会根据传入的目标数组大小的不同采取不同的排序方法。
小数组排序
在底层源码中,对小数组采用快速排序。如果数组的长度小于 QUICKSORT_THRESHOLD = 286
时,使用快速排序。
sql
// Use Quicksort on small arrays
if (right - left < QUICKSORT_THRESHOLD) {
sort(a, left, right, true);
return;
}
微小数组排序
对于更小的数组,采用插入排序。当数组长度小于 INSERTION_SORT_THRESHOLD = 47
时,采用插入排序。
css
// Use insertion sort on tiny arrays
if (length < INSERTION_SORT_THRESHOLD) {
if (leftmost) {
// Insertion sort on smallest arrays
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;
}
return;
}
}
大数组排序
对于大数组,首先进行一次数组遍历,标记数组的升序和降序的起始位置,然后根据数组的结构选择归并排序或快速排序。如果升序和降序序列的数量超过 MAX_RUN_COUNT = 67
,则采用快速排序。否则,采用归并排序。
css
/*
* 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) {
// Ascending sequence
if (a[k] < a[k + 1]) {
while (++k <= right && a[k - 1] <= a[k]);
}
// Descending sequence
else if (a[k] > a[k + 1]) {
while (++k <= right && a[k - 1] >= a[k]);
// Reverse the descending sequence
for (int lo = run[count] - 1, hi = k; ++lo < --hi; ) {
int t = a[lo];
a[lo] = a[hi];
a[hi] = t;
}
}
// Equal elements
else {
for (int m = MAX_RUN_LENGTH; ++k <= right && a[k - 1] == a[k]; ) {
if (--m == 0) {
sort(a, left, right, true);
return;
}
}
}
// Check if array is highly unstructured
if (++count == MAX_RUN_COUNT) {
sort(a, left, right, true);
return;
}
}
总的来说,Arrays.sort
在底层使用了快速排序、插入排序以及归并排序等算法,通过根据数组的大小和结构来选择合适的排序策略,以达到更好的性能。