Arrays.sort

今天看看這個(gè)經(jīng)常用的函數(shù)實(shí)現(xiàn)原理
基于jdk1.8

public static void sort(int[] a) {
DualPivotQuicksort.sort(a, 0, a.length - 1, null, 0, 0);
}

我們就用這個(gè)為例子走一邊流程:
我們可以看到其實(shí)sort它調(diào)用的是DualPivotQuicksort.sort這樣一個(gè)靜態(tài)方法焦影。
這個(gè)類中规个,我們先看看有些常量:
* If the length of an array to be sorted is less than this
* constant, Quicksort is used in preference to merge sort.
*/
private static final int QUICKSORT_THRESHOLD = 286;

這個(gè)意思就是說在286以內(nèi)的時(shí)候瘾晃,arrays.sort排序是優(yōu)先使用快排而不是歸并排序

在sort中苗傅,
if (length < INSERTION_SORT_THRESHOLD)

如果length小于47 那么用直接插入排序
* 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;

或者是pair insertion sort

*   do {
                if (left >= right) {
                    return;
                }
            } while (a[++left] >= a[left - 1]);

            /*
             * Every element from adjoining part plays the role
             * of sentinel, therefore this allows us to avoid the
             * left range check on each iteration. Moreover, we use
             * the more optimized algorithm, so called pair insertion
             * sort, which is faster (in the context of Quicksort)
             * than traditional implementation of insertion sort.
             */
            for (int k = left; ++left <= right; k = ++left) {
                int a1 = a[k], a2 = a[left];

                if (a1 < a2) {
                    a2 = a1; a1 = a[left];
                }
                while (a1 < a[--k]) {
                    a[k + 2] = a[k];
                }
                a[++k + 1] = a1;

                while (a2 < a[--k]) {
                    a[k + 1] = a[k];
                }
                a[k + 1] = a2;
            }
            int last = a[right];

            while (last < a[--right]) {
                a[right + 1] = a[right];
            }
            a[right + 1] = last;

這個(gè)條件是用leftmore實(shí)現(xiàn)的剪况,后面的是用于具有連續(xù)增長子序列的時(shí)候用的瓢湃,用兩個(gè)a1,a2分別表示遍歷的兩個(gè)相鄰的數(shù)挤巡,保證a1大于a2秽浇,先找到a1應(yīng)該所在的位置冀膝,在從a1位置向前找到a2的位置唁奢。
當(dāng)然這一切必須保證數(shù)組長度為偶數(shù),如果是奇數(shù)在對末尾的數(shù)進(jìn)行排序窝剖。

如果大于47 則用改進(jìn)過的快排麻掸。
首先將所有的數(shù)據(jù)段分為7段,
* int e3 = (left + right) >>> 1; // The midpoint
int e2 = e3 - seventh;
int e1 = e2 - seventh;
int e4 = e3 + seventh;
int e5 = e4 + seventh;

如果這五個(gè)數(shù)大小都不同

a[e2] = a[left];
a[e4] = a[right];

        /*
         * Skip elements, which are less or greater than pivot values.
         */
        while (a[++less] < pivot1);
        while (a[--great] > pivot2);

        /*
         * Partitioning:
         *
         *   left part           center part                   right part
         * +--------------------------------------------------------------+
         * |  < pivot1  |  pivot1 <= && <= pivot2  |    ?    |  > pivot2  |
         * +--------------------------------------------------------------+
         *               ^                          ^       ^
         *               |                          |       |
         *              less                        k     great
         *
         * Invariants:
         *
         *              all in (left, less)   < pivot1
         *    pivot1 <= all in [less, k)     <= pivot2
         *              all in (great, right) > pivot2
         *
         * Pointer k is the first index of ?-part.
         */

正如圖中所寫的赐纱,它其實(shí)找到了小于pivot1的臨界值和大于pivot2的臨界值脊奋。
* outer:
for (int k = less - 1; ++k <= great; ) {
int ak = a[k];
if (ak < pivot1) { // Move a[k] to left part
a[k] = a[less];
/*
* 這段代碼是將比pivot1小的值移到左端
/
a[less] = ak;
++less;
} else if (ak > pivot2) { 移到到右端
while (a[great] > pivot2) {
if (great-- == k) {
break outer;
}
}
if (a[great] < pivot1) { // a[great] <= pivot2
a[k] = a[less];
a[less] = a[great];
++less;
} else { // pivot1 <= a[great] <= pivot2
a[k] = a[great];
}
/

* Here and below we use "a[i] = b; i--;" instead
* of "a[i--] = b;" due to performance issue.
*/
a[great] = ak;
--great;
}
}

將整個(gè)數(shù)據(jù)段分為小于pivot1 大于pivot2 以及兩個(gè)之間的三個(gè)數(shù)據(jù)段

*       sort(a, left, less - 2, leftmost);
        sort(a, great + 2, right, false);

將第一和第三數(shù)據(jù)段排序采郎,接著在第二段中分成等于pivot1 等于pivot2以及其他的,
再對中間的進(jìn)行排序狂魔。這么一來蒜埋,這種可能就排序完了。

還有一種如果五個(gè)值有相同的話最楷,用e3作為分界線整份。
這個(gè)和上面的是差不多的,只是分成大于pivot 等于pivot 和小于pivot
再遞歸排序就好了

以上是小于286 大于286的時(shí)候用來另一種方法籽孙。

int[] run = new int[MAX_RUN_COUNT + 1];

代碼中用了這個(gè)數(shù)字去衡量這個(gè)排序的數(shù)組是否具有局部有序性烈评。

if (++count == MAX_RUN_COUNT) {
sort(a, left, right, true);
return;
}

無序的情況下直接有快排就行了。
如果有序的情況下直接用歸并排序犯建。

讀源碼讲冠,是我們了解大神領(lǐng)域的一大捷徑
生命不息,奮斗不止

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末适瓦,一起剝皮案震驚了整個(gè)濱河市竿开,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌玻熙,老刑警劉巖否彩,帶你破解...
    沈念sama閱讀 217,185評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異嗦随,居然都是意外死亡列荔,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,652評論 3 393
  • 文/潘曉璐 我一進(jìn)店門枚尼,熙熙樓的掌柜王于貴愁眉苦臉地迎上來贴浙,“玉大人,你說我怎么就攤上這事署恍∑槔#” “怎么了?”我有些...
    開封第一講書人閱讀 163,524評論 0 353
  • 文/不壞的土叔 我叫張陵锭汛,是天一觀的道長笨奠。 經(jīng)常有香客問我,道長唤殴,這世上最難降的妖魔是什么般婆? 我笑而不...
    開封第一講書人閱讀 58,339評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮朵逝,結(jié)果婚禮上蔚袍,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好啤咽,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,387評論 6 391
  • 文/花漫 我一把揭開白布晋辆。 她就那樣靜靜地躺著,像睡著了一般宇整。 火紅的嫁衣襯著肌膚如雪瓶佳。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,287評論 1 301
  • 那天鳞青,我揣著相機(jī)與錄音霸饲,去河邊找鬼。 笑死臂拓,一個(gè)胖子當(dāng)著我的面吹牛厚脉,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播胶惰,決...
    沈念sama閱讀 40,130評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼傻工,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了孵滞?” 一聲冷哼從身側(cè)響起中捆,我...
    開封第一講書人閱讀 38,985評論 0 275
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎剃斧,沒想到半個(gè)月后轨香,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體忽你,經(jīng)...
    沈念sama閱讀 45,420評論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡幼东,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,617評論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了科雳。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片根蟹。...
    茶點(diǎn)故事閱讀 39,779評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖糟秘,靈堂內(nèi)的尸體忽然破棺而出简逮,到底是詐尸還是另有隱情,我是刑警寧澤尿赚,帶...
    沈念sama閱讀 35,477評論 5 345
  • 正文 年R本政府宣布散庶,位于F島的核電站,受9級特大地震影響凌净,放射性物質(zhì)發(fā)生泄漏悲龟。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,088評論 3 328
  • 文/蒙蒙 一冰寻、第九天 我趴在偏房一處隱蔽的房頂上張望须教。 院中可真熱鬧,春花似錦、人聲如沸轻腺。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,716評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽贬养。三九已至挤土,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間误算,已是汗流浹背耕挨。 一陣腳步聲響...
    開封第一講書人閱讀 32,857評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留尉桩,地道東北人筒占。 一個(gè)月前我還...
    沈念sama閱讀 47,876評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像蜘犁,于是被迫代替她去往敵國和親翰苫。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,700評論 2 354

推薦閱讀更多精彩內(nèi)容