简介:
在1.8之前的版本中对此方法进行了重写,如果还需要使用之前的排序算法,需要加上系统属性java.util.Arrays.useLegacyMergeSort=true,之前的排序使用优化后的归并排序,在1.8中使用TimSort算法来进行排序,TimSort算法是由Tim Peters在2002提出并首先实现在了phtyon中,是结合了合并排序(merge sort)和插入排序(insertion sort)的一种高效稳定的算法。算法原理看这里 https://blog.csdn.net/yangzhongblog/article/details/8184707
Arrays.sort(Object[] a)分析
1、 方法声明
/**
* 根据Comparable的自然排序将给定数组升序排序。所有元素必须实现Comparable 接口
* 而且,所有元素能相互比较,不然可能会抛出ClassCastException异常
*
* 此排序确保是稳定的,如果两个元素e1.equals(e2),那么他们不会被再次排序
*
* 该实现是一个稳定、自适应、重复的归并排序,当给定数组是局部排序的数组时它的时间复杂度比 nlogn更小,
* 然而当给定数组是随机排序,它与传统的归并排序性能相同。如果给定数组大体有序,该算法只需要大概n次比较即可完成排序。
*
* 该算法在输入数组为升序或降序时都能发挥优势,并且在该数组部分有序的情况下也能发挥其优势,
* 它能通过简单连接即可很好的完成将多个数组进行合并
*/
public static void sort(Object[] a) {
//如果要兼容1.8之前的排序程序,在系统属性中需要添加属性,如:java -jar -Djava.Arrays.uselegacyMergeSort=true xx.jar
if (LegacyMergeSort.userRequested)
legacyMergeSort(a);
else
//真正的TimSort算法实现在ComparableTimSort中
ComparableTimSort.sort(a, 0, a.length, null, 0, 0);
}
2、 ComparableTimSort.sort(Object[] a, int lo, int hi, Object[] work, int workBase, int workLen)分析
/**
* 将数组指定范围内的元素排序
*
* [@param](https://my.oschina.net/u/2303379) a 被排序数组
* [@param](https://my.oschina.net/u/2303379) lo 排序开始元素index
* [@param](https://my.oschina.net/u/2303379) hi 排序结束元素index,不包含此index
* [@param](https://my.oschina.net/u/2303379) work a workspace array (slice)
* [@param](https://my.oschina.net/u/2303379) workBase origin of usable space in work array
* @param workLen usable size of work array
* @since 1.8
*/
static void sort(Object[] a, int lo, int hi, Object[] work, int workBase, int workLen) {
//保证数组的合法性
assert a != null && lo >= 0 && lo <= hi && hi <= a.length;
int nRemaining = hi - lo;
//对于只有0|1个元素的数组,不需要进行排序
if (nRemaining < 2)
return; // Arrays of size 0 and 1 are always sorted
// If array is small, do a "mini-TimSort" with no merges
//如果数组比较小,直接使用二叉插入排序进行排序
if (nRemaining < MIN_MERGE) {
//计算数组头部递增或递减的的序列长度,如果是递减,则翻转,保持升序
int initRunLen = countRunAndMakeAscending(a, lo, hi);
//使用二叉插入排序对在initRunLen后的元素进行排序
binarySort(a, lo, hi, lo + initRunLen);
return;
}
/**
* March over the array once, left to right, finding natural runs,
* extending short natural runs to minRun elements, and merging runs
* to maintain stack invariant.
*/
//构造ComparableTimSort对象
ComparableTimSort ts = new ComparableTimSort(a, work, workBase, workLen);
//计算最小run的长度
int minRun = minRunLength(nRemaining);
do {
// Identify next run
//计算当前排序的run的长度,如果为递减数组则翻转
int runLen = countRunAndMakeAscending(a, lo, hi);
// If run is short, extend to min(minRun, nRemaining)
//如果当前run的长度小于minRun,则进行扩展,在扩展过程中使用二叉排序来排序扩展的的元素
if (runLen < minRun) {
int force = nRemaining <= minRun ? nRemaining : minRun;
binarySort(a, lo, lo + force, lo + runLen);
runLen = force;
}
// Push run onto pending-run stack, and maybe merge
//将此run放入栈中
ts.pushRun(lo, runLen);
//执行合并逻辑,合并的时候也做了一些优化
ts.mergeCollapse();
// Advance to find next run
lo += runLen;
nRemaining -= runLen;
} while (nRemaining != 0);
// Merge all remaining runs to complete sort
assert lo == hi;
//保证最后的run都被合并
ts.mergeForceCollapse();
assert ts.stackSize == 1;
}