Array.sort()
核心思路
根據不同的情況,選擇不同的排序算法。
1、當需要排列的元素較少的時候,采用普通的插入排序
當被排序的數組長度小於47但排序不是從數組起始位置開始的時候,那么就會選擇哨兵插入排序的方式進行排序。
這種情況主要是當sort被雙基准快排遞歸調用的時候才會使用
2、如果元素較多,大於插入排序的閾值,但是小於歸並排序的閾值,這時采用快速排序
在進行快排之前,首先會將這個不長不斷的數組按照1/7的長度划分,最后划分后的結果為:
// Inexpensive approximation of length / 7
int seventh = (length >> 3) + (length >> 6) + 1;
/*
* Sort five evenly spaced elements around (and including) the
* center element in the range. These elements will be used for
* pivot selection as described below. The choice for spacing
* these elements was empirically determined to work well on
* a wide variety of inputs.
*/
int e3 = (left + right) >>> 1; // The midpoint
int e2 = e3 - seventh;
int e1 = e2 - seventh;
int e4 = e3 + seventh;
int e5 = e4 + seventh;
然后對這5個划分點進行排序:
2.1 如果這五個划分點的數據倆倆各不相同,則以第一個划分點和最后一個划分點作為基准點,采用雙基准快排;
采用雙基准快排也有優化的地方,如果中間的元素過多(超過整個排序部分的七分之四),將會針對這一區間內的重復鍵進行優化。
與基准1和基准2 相同的鍵將會被分到前后兩個分區,並會被從接下來要繼續遞歸排序的中間分區中剔除,盡可能減少了中間分區的大小。
for (int k = less - 1; ++k <= great; ) {
int ak = a[k];
if (ak == pivot1) { // Move a[k] to left part
a[k] = a[less];
a[less] = ak;
++less;
} else if (ak == pivot2) { // Move a[k] to right part
while (a[great] == pivot2) {
if (great-- == k) {
break outer;
}
}
if (a[great] == pivot1) { // a[great] < pivot2
a[k] = a[less];
/*
* Even though a[great] equals to pivot1, the
* assignment a[less] = pivot1 may be incorrect,
* if a[great] and pivot1 are floating-point zeros
* of different signs. Therefore in float and
* double sorting methods we have to use more
* accurate assignment a[less] = a[great].
*/
a[less] = pivot1;
++less;
} else { // pivot1 < a[great] < pivot2
a[k] = a[great];
}
a[great] = ak;
--great;
}
}
2.2 如果這五個划分點有相同的情況,則采用三路快排。
3、如果數組的長度超過了快排的閾值
首先進行有序性的判斷,判斷這個數組是否是基本有序
將有序部分中斷處的位置記錄下來,如果中斷個數大於某個閾值則判斷為無序,反之有序。
3.1 如果是基本有序,則采用歸並方式排序,這里會按照剛才記錄的有序部分的中斷點作為歸並點。
3.2 如果判定為無序,則依然采用快排。