参考:https://www.cnblogs.com/gw811/archive/2012/10/04/2711746.html
查看Arrays.sort()的源码可以看到
Java Arrays中提供了对所有类型的排序。其中主要分为针对基本类型(除了boolean)和Object两大类。
1.基本类型数组的排序
其中针对于基本数据类型调用的是DualPivotQuicksort类的sort()方法
对于基本数据类型的数组,假设数组长度为length:
如果length<47,那么采用插入排序算法。
如果47<=length<286,或者286<=length,但数组不具备特定结构,那么使用快速排序的一种优化形式:双轴快排算法。
如果286<=length,并且数组具备特定结构,那么使用归并排序算法。
1.1数组是否具备特定结构
在判断是否使用归并排序前,要先判断数组是否具备特定结构,这是一个什么意思呢?
// 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,9,8,7,6,8。9到6是降序,为一个组,然后把降序的一组排成升序:1,6,7,8,9,8。然后再从最后的8开始继续往后面找。
每遇到这样一个降序组,++count,当count大于MAX_RUN_COUNT(67),被判断为这个数组不具备结构,也就是说这数据时而升时而降,波峰波谷太多,排列太过陡峭,说明不适合采用归并排序,还是使用快速排序为宜。
如果count少于MAX_RUN_COUNT(67)的,说明这个数组还有点结构,就继续往下走下面的归并排序。
2. 对象类型数组的排序
对于对象类型的数组,假设数组长度为length:
如果length<32,那么采用不包含合并操作的mini-TimSort算法。
如果32<=length,那么采用完整TimSort排序算法(一种结合了归并排序和插入排序的算法)。
3. 为什么要采用不同的算法?
对于长度较小的数组使用插入排序这很好理解,虽然插入排序的时间复杂度为O(n^2),但在n较小的情况下,插入排序性能要高于快速排序。
其次我们要知道,在n的数量较大时,归并排序和快速排序,都是性能最优的排序算法,他们的时间复杂度平均都在O(nlogn)左右,只不过区别在于归并排序是稳定的,快速排序是不稳定的。
稳定是指相等的数据在排序之后仍然按照排序之前的前后顺序排列。
对于基本数据类型,稳定性没有意义,所以它可以使用不稳定的快排(当然它也使用了归并排序)
而对于对象类型,稳定性是比较重要的,因为对象相等的判断比较复杂,我们无法寄希望于每个程序员都会重写准确的equal方法,故而稳妥起见,最好相等对象尽量保持排序前的顺序,故而我们使用都是稳定算法的归并排序和插入排序结合而成的TimSort算法。
另外一个原因是归并排序的比较次数比快排少,移动(对象引用的移动)次数比快排多,而对于对象来说,比较是相对耗时的操作,所以它不适合使用快排。
而对于基本数据类型来说,比较和移动都不怎么耗时,所以它用归并或者快排都可以
4.总结
基本数据类型数组使用快排+归并是因为:
基本数据类型无所谓稳定性,可以采用非稳定的快排。
对于基本数据类型来说,比较和移动都不怎么耗时,所以它用归并或者快排都可以。
对象数据类型数组使用TimSort排序是因为(或者换句话说,对象数据类型不使用快排是因为):
对象数据类型要求稳定性,需要采用稳定的归并+插入。
对于对象来说,比较操作相对耗时,所以用比较操作较少的归并排序可以扬长避短。