快速排序及其優(yōu)化

算法簡(jiǎn)介

是一種分治的排序算法恩伺,特點(diǎn)就是快徙瓶,而且效率高。

基本思路

通過(guò)一趟排序?qū)⒋旁胤指舫瑟?dú)立的兩部分烹困,其中一部分元素的關(guān)鍵字均比另一部分的關(guān)鍵字小玄妈,然后分別對(duì)這兩部分元素繼續(xù)進(jìn)行排序,以達(dá)到整個(gè)序列有序。

Q:對(duì)比歸并排序拟蜻,有何異同绎签?
A:快速排序和歸并排序是互補(bǔ)的:歸并排序是將數(shù)組分成兩個(gè)子數(shù)組分別排序,并將有序的子數(shù)組歸并以整個(gè)數(shù)組排序酝锅;而快速排序是當(dāng)兩個(gè)子數(shù)組都有序時(shí),整個(gè)數(shù)組也就自然有序了。

遞歸調(diào)用先后順序不同歸并排序 ~ 遞歸調(diào)用發(fā)生在處理整個(gè)數(shù)組之前单雾;快速排序 ~ 遞歸調(diào)用發(fā)生在處理整個(gè)數(shù)組之后羡棵。

切分?jǐn)?shù)組的位置不同歸并 ~ 一個(gè)數(shù)組等分為兩半;快速 ~ 切分的位置取決于數(shù)組的內(nèi)容稿蹲。

運(yùn)行軌跡

快速排序遞歸的將子數(shù)組 arr[lo...hi] 排序扭勉,先用 partition() 方法將 arr[indexJ] 放到一個(gè)適合位置,然后再用遞歸調(diào)用將其他位置的元素排序

算法的遞歸調(diào)用過(guò)程

快速排序關(guān)鍵在于切分方法苛聘,我們就是通過(guò)遞歸地調(diào)用切分來(lái)排序的涂炎,因?yàn)?strong>切分過(guò)程總是能排定一個(gè)元素。

實(shí)現(xiàn)的一般策略
①设哗、隨意地取 arr[lo] 作為切分元素(將會(huì)排定的元素)唱捣;
②、從數(shù)組的左端開(kāi)始网梢,向右端掃描爷光,直到找到一個(gè) >= 切分元素的元素;
③澎粟、從數(shù)組的右端開(kāi)始蛀序,向左端掃描,直到找到一個(gè) <= 切分元素的元素活烙;
④徐裸、交換他倆的位置(因?yàn)轱@然他倆沒(méi)有被排定);
⑤啸盏、如此繼續(xù)重贺,可以保證左指針 indexI 的左側(cè)元素都 <= 切分元素、右側(cè)指針 indexJ 的右側(cè)元素都 >= 切分元素回懦;
⑥气笙、當(dāng)兩個(gè)指針相遇時(shí),交換切分元素 arr[lo]arr[indexJ] 并返回 indexJ 即可怯晕。

代碼實(shí)現(xiàn)

根據(jù)排序算法類(lèi)的模板實(shí)現(xiàn)快速排序(提醒:點(diǎn)藍(lán)字查看詳情)

/**
 * 標(biāo)準(zhǔn)的快速排序
 *
 * @author TinyDolphin
 * 2017/11/13 14:20.
 */
public class Quick {

    public static void sort(Comparable[] arr) {
        shuffle(arr); // 打亂數(shù)組潜圃,避免切分不平衡,帶來(lái)的低效
        sort(arr, 0, arr.length - 1);
    }

    private static void sort(Comparable[] arr, int lo, int hi) {
        if (hi <= lo) return;
        int indexJ = partition(arr, lo, hi); // 切分方法
        sort(arr, lo, indexJ - 1);
        sort(arr, indexJ + 1, hi);
    }

    // 打亂數(shù)組的方法
    private static void shuffle(Comparable[] arr) {
        int length = arr.length;
        Random random = new Random(System.currentTimeMillis());
        for (int index = 0; index < length; index++) {
            int temp = random.nextInt(length);
            exch(arr,index,temp);
        }
    }

    /**
     * 關(guān)鍵:切分方法
     * 該過(guò)程使得數(shù)組滿足下面兩個(gè)條件:
     *    ①舟茶、對(duì)于某個(gè) indexJ谭期、arr[indexJ] 已經(jīng)排定堵第;
     *    ②、arr[lo...indexJ-1] <= arr[indexJ] <= arr[indexJ+1...hi]
     */
    private static int partition(Comparable[] arr, int lo, int hi) {
        int indexI = lo;            // 左右掃描指針
        int indexJ = hi + 1;        
        Comparable temp = arr[lo];    //切分元素
        while (true) {
            // 從數(shù)組的左端開(kāi)始隧出,向右端掃描踏志,直到找到一個(gè) >= 切分元素的元素;
            while (less(arr[++indexI], temp)) {
                if (indexI == hi) break;
            }
            // 從數(shù)組的右端開(kāi)始胀瞪,向左端掃描针余,直到找到一個(gè) <= 切分元素的元素;
            while (less(temp, arr[--indexJ])) {
                if (indexJ == lo) break;
            }
            // 指針相遇凄诞,退出循環(huán)
            if (indexI >= indexJ) break;
            // 交換他倆的位置(因?yàn)轱@然他倆沒(méi)有被排定)
            exch(arr, indexI, indexJ);
        }
        exch(arr, lo, indexJ);      // 將 temp = arr[indexJ] 放入正確的位置
        return indexJ;             // arr[lo...indexJ-1] <= arr[indexJ] <= arr[indexJ+1...hi] 達(dá)成
    }
    ...
}

Q:打亂數(shù)組的方法(shuffle())消耗了大量的時(shí)間圆雁,這么做值得么?
A:值得幔摸,這樣可以預(yù)防出現(xiàn)最壞情況并使時(shí)間可以預(yù)計(jì)摸柄。

實(shí)現(xiàn)細(xì)節(jié)必須注意

①、原地切分:如果使用一個(gè)輔助數(shù)組既忆,我們可以很容易實(shí)現(xiàn)切分驱负,但將切分后的數(shù)組復(fù)制回去的開(kāi)銷(xiāo)也許會(huì)使我們得不償失。
②患雇、別越界:如果切分元素是數(shù)組中最小或最大的那個(gè)元素跃脊,我們就要小心別讓掃描指針跑出數(shù)組的邊界。parttion() 實(shí)現(xiàn)可以進(jìn)行明確的檢測(cè)來(lái)預(yù)防苛吱。測(cè)試條件 ( indexJ==lo ) 是冗余的酪术,因?yàn)榍蟹衷鼐褪?arr[lo],它不可能比自己小翠储。數(shù)組右端也有相同的情況绘雁,他們都是可以去掉的。(練習(xí) 2.3.17)
③援所、保持隨機(jī)性:數(shù)組元素的順序是被打亂過(guò)的庐舟。保存隨機(jī)性的另一種方法:在切分方法隨機(jī)選擇一個(gè)切分元素
④住拭、終止循環(huán):一個(gè)最常見(jiàn)的錯(cuò)誤是沒(méi)有考慮到數(shù)組中可能包含和切分元素的值相同的其他元素挪略。
⑤、處理切分元素值有重復(fù)的情況:左側(cè)掃描最好遇到 >= 切分元素值 的元素時(shí)停下滔岳,右側(cè)掃描則是遇到 <= 切分元素值的元素時(shí)停下杠娱。(盡管存在一些等值交換,但可以避免算法的運(yùn)行時(shí)間變?yōu)槠椒郊?jí)別
⑥谱煤、終止遞歸:一定要保證將切分元素放入正確的位置摊求,不然容易導(dǎo)致無(wú)限遞歸。

性能分析

最佳情況:T(n) = O(nlogn)
最差情況:T(n) = O(n2)
平均情況:T(n) = O(nlogn)

將長(zhǎng)度為 N 的無(wú)重復(fù)數(shù)組排序趴俘,快排平均需要 ~2NlnN 次比較以及 1/6 的交換

快排最多需要約 N2/2 次比較睹簇,但隨機(jī)打亂數(shù)組能夠預(yù)防這種情況奏赘。

優(yōu)化方案

①寥闪、切換到插入排序
對(duì)于小數(shù)組太惠,快排比插入慢;因?yàn)檫f歸疲憋,快排的 sort() 方法在小數(shù)組中也會(huì)調(diào)用自己凿渊。
②、三取樣切分(用來(lái)選擇切分元素)
使用子數(shù)組的一小部分元素的中位數(shù)來(lái)切分?jǐn)?shù)組(取樣大小為 3 并用大小居中的元素效果最好) || 將取樣元素放在數(shù)組末尾作為去掉 partition() 中的數(shù)組邊界測(cè)試缚柳。

優(yōu)化代碼 NO.1:插入排序+三取樣切分
/**
 * 快速排序優(yōu)化
 *
 * 插入排序+三取樣切分
 *
 * @author TinyDolphin
 * 2017/11/14 13:41.
 */
public class QuickBar {

    private static final int CUTOFF = 8;

    public static void sort(Comparable[] arr) {
        //shuffle(arr); // 讓數(shù)組成為隨機(jī)數(shù)組埃脏,避免切分不平衡,帶來(lái)的低效
        sort(arr, 0, arr.length - 1);
    }

    private static void sort(Comparable[] arr, int lo, int hi) {
        int n = hi - lo + 1;
        // 當(dāng)子數(shù)組的長(zhǎng)度為 8 時(shí)秋忙,調(diào)用插入排序
        if (n <= CUTOFF) {
            insertionSort(arr, lo, hi);
            return;
        }
        // 調(diào)用三取樣切分
        int m = median3(arr, lo, lo + n / 2, hi);
        exch(arr, m, lo);
        int indexJ = partition(arr, lo, hi); // 切分方法
        sort(arr, lo, indexJ - 1);
        sort(arr, indexJ + 1, hi);
    }

    // 插入排序
    private static void insertionSort(Comparable[] arr, int lo, int hi) {
        for (int indexI = lo; indexI <= hi; indexI++) {
            for (int indexJ = indexI; indexJ > lo && less(arr[indexJ], arr[indexJ - 1]); indexJ--) {
                exch(arr, indexJ, indexJ - 1);
            }
        }
    }

    // 選擇切分元素:取 arr[i]  arr[j]   arr[k]  三個(gè)元素值的中間元素的下標(biāo)
    private static int median3(Comparable[] arr, int i, int j, int k) {
        return (less(arr[i], arr[j]) ?
                (less(arr[j], arr[k]) ? j : less(arr[i], arr[k]) ? k : i) :
                (less(arr[k], arr[j]) ? j : less(arr[k], arr[i]) ? k : i));
    }

    // 切分方法
    private static int partition(Comparable[] arr, int lo, int hi) {
        int indexI = lo;            // 左右掃描指針
        int indexJ = hi + 1;        // 切分元素
        Comparable temp = arr[lo];
        while (true) {
            // 從數(shù)組的左端開(kāi)始彩掐,向右端掃描,直到找到一個(gè) >= 切分元素的元素灰追;
            while (less(arr[++indexI], temp)) {
                if (indexI == hi) break;
            }
            // 從數(shù)組的右端開(kāi)始堵幽,向左端掃描,直到找到一個(gè) <= 切分元素的元素弹澎;
            while (less(temp, arr[--indexJ])) {
                if (indexJ == lo) break;
            }
            // 指針相遇朴下,退出循環(huán)
            if (indexI >= indexJ) break;
            // 交換他倆的位置(因?yàn)轱@然他倆沒(méi)有被排定)
            exch(arr, indexI, indexJ);
        }
        exch(arr, lo, indexJ);      // 將 temp = arr[indexJ] 放入正確的位置
        return indexJ;             // arr[lo...indexJ-1] <= arr[indexJ] <= arr[indexJ+1...hi] 達(dá)成
    }
    ...
}

③、熵最優(yōu)的排序
在應(yīng)對(duì)大量重復(fù)元素的情況下苦蒿,我們可以將數(shù)組切分為三部分殴胧,分別對(duì)應(yīng) 小于、等于和大于 切分元素的數(shù)組元素佩迟。

三向切分的快速排序

Dijkstra 的解法如“三向切分的快速排序”中極為簡(jiǎn)潔的切分代碼:它從左到右遍歷數(shù)組一次团滥,維護(hù)
一個(gè)指針 lt 使得 a[lo...lt-1] 中的元素都 < v;
一個(gè)指針 gt 使得 a[gt+1...hi] 中的元素都 > v 报强;
一個(gè)指針 i 使得 a[lt...i-1] 中的元素都 == v灸姊,a[i...gt] 中的元素都還未確定。


優(yōu)化代碼 NO.2:三向切分

對(duì)于存在大量重復(fù)元素的數(shù)組躺涝,這種方法比標(biāo)準(zhǔn)的快速排序的效率高得多厨钻。其他情況,可能不及優(yōu)化方案 NO.1坚嗜。

/**
 * 快速排序優(yōu)化:三向切分(用于解決大量重復(fù)元素)
 *
 * @author TinyDolphin
 * 2017/11/14 14:12.
 */
public class Quick3way {

    public static void sort(Comparable[] arr) {
        shuffle(arr);
        sort(arr, 0, arr.length - 1);
    }

    private static void sort(Comparable[] arr, int lo, int hi) {
        if (hi <= lo) {
            return;
        }
        int lt = lo;
        int gt = hi;
        Comparable v = arr[lo];
        int i = lo;
        while (i <= gt) {
            int cmp = arr[i].compareTo(v);
            // arr[i] < v夯膀,交換 arr[lt] & arr[i],將 lt & i 加一
            if (cmp < 0) {
                exch(arr, lt++, i++);
            }
            // arr[i] > v苍蔬,交換 arr[gt] & arr[i]诱建,將 gt 減一
            else if (cmp > 0) {
                exch(arr, i, gt--);
            }
            // arr[i] == v,將 i 加一
            else {
                i++;
            }
        }
        // arr[lo...lt-1] < v = arr[lt...gt] < arr[gt+1...hi]
        sort(arr, lo, lt - 1);
        sort(arr, gt + 1, hi);
    }

    // 打亂數(shù)組的方法
    private static void shuffle(Comparable[] arr) {
        int length = arr.length;
        Random random = new Random(System.currentTimeMillis());
        for (int index = 0; index < length; index++) {
            int temp = random.nextInt(length);
            exch(arr, index, temp);
        }
    }
    ...
}
優(yōu)化代碼 NO.3:插入排序+三取樣切分+三向切分

優(yōu)化了三向切分代碼碟绑,加快了處理大量重復(fù)元素的速度俺猿,但是其他情況下茎匠,速度還是不及NO.1

/**
 * 快速排序優(yōu)化
 *
 * 插入排序+三取樣切分+三向切分
 *
 * @author TinyDolphin
 * 2017/11/14 17:11.
 */
public class Quick3wayBar {

    private static final int CUTOFF = 8;

    public static void sort(Comparable[] arr) {
        //shuffle(arr);
        sort(arr, 0, arr.length - 1);
    }

    private static void sort(Comparable[] arr, int lo, int hi) {
        int n = hi - lo + 1;
        // 當(dāng)子數(shù)組的長(zhǎng)度為 8 時(shí),調(diào)用插入排序
        if (n <= CUTOFF) {
            insertionSort(arr, lo, hi);
            return;
        }
        // 調(diào)用三取樣切分
        int m = median3(arr, lo, lo + n / 2, hi);
        exch(arr, m, lo);

        int lt = lo;
        int gt = hi;
        Comparable v = arr[lo];
        int i = lo;
        while (i <= gt) {
            int cmp = arr[i].compareTo(v);
            // arr[i] < v押袍,交換 arr[lt] & arr[i]诵冒,將 lt & i 加一
            if (cmp < 0) {
                exch(arr, lt++, i++);
            }
            // arr[i] > v,交換 arr[gt] & arr[i]谊惭,將 gt 減一
            else if (cmp > 0) {
                exch(arr, i, gt--);
            }
            // arr[i] == v汽馋,將 i 加一
            else {
                i++;
            }
        }
        // arr[lo...lt-1] < v = arr[lt...gt] < arr[gt+1...hi]
        sort(arr, lo, lt - 1);
        sort(arr, gt + 1, hi);
    }

    // 插入排序
    private static void insertionSort(Comparable[] arr, int lo, int hi) {
        for (int indexI = lo; indexI <= hi; indexI++) {
            for (int indexJ = indexI; indexJ > lo && less(arr[indexJ], arr[indexJ - 1]); indexJ--) {
                exch(arr, indexJ, indexJ - 1);
            }
        }
    }

    // 取 arr[i]  arr[j]   arr[k]  三個(gè)元素值的中間元素的下標(biāo)
    private static int median3(Comparable[] arr, int i, int j, int k) {
        return (less(arr[i], arr[j]) ?
                (less(arr[j], arr[k]) ? j : less(arr[i], arr[k]) ? k : i) :
                (less(arr[k], arr[j]) ? j : less(arr[k], arr[i]) ? k : i));
    }
優(yōu)化代碼 NO.4:快速三向切分

優(yōu)化:插入排序 + 三取樣切分 + Tukey's ninther + Bentley-McIlroy 三向切分

Tukey's ninther 方法選擇切分元素:選擇三組,每組三個(gè)元素圈盔,分別取三組元素的中位數(shù)豹芯,然后去三個(gè)中位數(shù)的中位數(shù)作為切分元素。

原理:將重復(fù)元素放置于子數(shù)組兩端的方式實(shí)現(xiàn)一個(gè)信息量最優(yōu)的排序算法驱敲。


/**
 * 三向切分-快速排序優(yōu)化
 *
 * 插入排序 + 三取樣切分 + Tukey's ninther + Bentley-McIlroy 三向切分
 *
 * @author TinyDolphin
 * 2017/11/15 15:16.
 */
public class QuickX {

    private static final int INSERTION_SORT_CUTOFF = 8;

    private static final int MEDIAN_OF_3_CUTOFF = 40;

    public static void sort(Comparable[] arr) {
        sort(arr, 0, arr.length - 1);
    }

    private static void sort(Comparable[] a, int lo, int hi) {
        int n = hi - lo + 1;

        // 當(dāng)子數(shù)組大小 <= 8 時(shí)铁蹈,切換到插入排序
        if (n <= INSERTION_SORT_CUTOFF) {
            insertionSort(a, lo, hi);
            return;
        }

        // 當(dāng)子數(shù)組大小 <= 40 時(shí),使用三取樣切分(median-of-3)選擇切分元素
        else if (n <= MEDIAN_OF_3_CUTOFF) {
            int m = median3(a, lo, lo + n / 2, hi);
            exch(a, m, lo);
        }

        // 當(dāng)子數(shù)組大小 > 40 時(shí)众眨,使用 Tukey's ninther 方法選擇切分元素
        else {
            int eps = n / 8;
            int mid = lo + n / 2;
            int m1 = median3(a, lo, lo + eps, lo + eps + eps);
            int m2 = median3(a, mid - eps, mid, mid + eps);
            int m3 = median3(a, hi - eps - eps, hi - eps, hi);
            int ninther = median3(a, m1, m2, m3);
            exch(a, ninther, lo);
        }

        // 使用 Bentley-McIlroy 三向切分
        // 使數(shù)組 a[lo...p-1] & a[q+1...hi] == v ; a[p...i-1] < a[lo] < a[j+1...q]
        int i = lo, j = hi + 1;
        int p = lo, q = hi + 1;
        Comparable v = a[lo];
        while (true) {
            // 移動(dòng)指針握牧,使得 a[p..i-1] < a[lo] == v,直到一個(gè) >= v 的元素a[i]
            while (less(a[++i], v))
                if (i == hi) break;
            // 移動(dòng)指針围辙,使得 a[lo] == v > a[j+1...q]我碟,直到一個(gè) <= v 的元素a[j]
            while (less(v, a[--j]))
                if (j == lo) break;

            // 指針交叉時(shí),剛好 a[i] == v 的情況下姚建,交換以將 a[i] 歸位
            if (i == j && eq(a[i], v))
                exch(a, ++p, i);
            // 排序完成矫俺,退出循環(huán)
            if (i >= j) break;

            // 交換 a[i] & a[j] 的值,使其歸位
            exch(a, i, j);
            // 如果 a[i] == v掸冤,交換 a[p] & a[i]厘托,使其歸位
            if (eq(a[i], v)) exch(a, ++p, i);
            // 如果 a[j] == v,交換 a[q] & a[i]稿湿,使其歸位
            if (eq(a[j], v)) exch(a, --q, j);
        }


        // 在切分循環(huán)結(jié)束后铅匹,將和 v 相等的元素交換到正確位置
        // 即使數(shù)組 a[lo...j-1] < v == a[j...i] < a[i+1...hi]
        i = j + 1;
        // 把 v == a[lo...p-1] 元素歸位到 a[j...i] 中
        for (int k = lo; k <= p; k++)
            exch(a, k, j--);
        // 把 v == a[q+1...hi] 元素歸位到 a[j...i] 中
        for (int k = hi; k >= q; k--)
            exch(a, k, i++);

        // 遞歸調(diào)用
        sort(a, lo, j);
        sort(a, i, hi);
    }


    // 插入排序
    private static void insertionSort(Comparable[] arr, int lo, int hi) {
        for (int indexI = lo; indexI <= hi; indexI++) {
            for (int indexJ = indexI; indexJ > lo && less(arr[indexJ], arr[indexJ - 1]); indexJ--) {
                exch(arr, indexJ, indexJ - 1);
            }
        }
    }

    // 取 arr[i]  arr[j]   arr[k]  三個(gè)元素值的中間元素的下標(biāo)
    private static int median3(Comparable[] arr, int i, int j, int k) {
        return (less(arr[i], arr[j]) ?
                (less(arr[j], arr[k]) ? j : less(arr[i], arr[k]) ? k : i) :
                (less(arr[k], arr[j]) ? j : less(arr[k], arr[i]) ? k : i));
    }

    // 判斷兩個(gè)元素是否相等
    private static boolean eq(Comparable v, Comparable w) {
        return v.compareTo(w) == 0;
    }
    ...
}
優(yōu)化代碼 NO.5:最簡(jiǎn)單的實(shí)現(xiàn)之一

但是碰到大量重復(fù)元素的話,可能會(huì)變成 O(n2)

/**
 * 快速排序最簡(jiǎn)單的實(shí)現(xiàn)方式之一
 *
 * @author TinyDolphin
 * 2017/11/15 16:38.
 */
public class QuickKR {

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

    private static void sort(Comparable[] a, int lo, int hi) {
        if (hi <= lo) return;
        exch(a, lo, (lo + hi) / 2);  // use middle element as partition
        int last = lo;
        for (int i = lo + 1; i <= hi; i++)
            if (less(a[i], a[lo])) exch(a, ++last, i);
        exch(a, lo, last);
        sort(a, lo, last-1);
        sort(a, last+1, hi);
    }
    ...
}
測(cè)試代碼
    public static void main(String[] args) {
        int length = 1000000;  // 百萬(wàn)數(shù)據(jù)量級(jí)別
        Integer[] arr = new Integer[length];
        for (int index = 0; index < length; index++) {
            // 隨機(jī)數(shù)組
            arr[index] = new Random().nextInt(length) + 1;
            // 大量重復(fù)元素的數(shù)組
            // arr[index] = new Random().nextInt(100) + 1;
        }

        long start = System.currentTimeMillis();
        sort(arr);
        long end = System.currentTimeMillis();
        System.out.println("耗費(fèi)時(shí)間:" + (end - start) + "ms");
    }
測(cè)試結(jié)果
隨機(jī)數(shù)組 重復(fù)數(shù)組 升序數(shù)組 降序數(shù)組
MergePlus.sort() 1127ms 827ms 60ms 401ms
Array.sort() 1706ms 1096ms 30ms 94ms
Quick 1573ms 900ms 1343ms 1242ms
QuickBar 846ms 659ms 251ms 溢出
Quick3way 2191ms 543ms 1635ms 1606ms
Quick3wayBar 1513ms 343ms 11146ms 11588ms
QuickX 1331ms 553ms 228ms 528ms
QuickKR 1325m 21270ms 347ms 423ms

Merge:歸并排序
MergePlus:表示快排的優(yōu)化實(shí)現(xiàn)
QuickBar:插入排序+三取樣切分
Quick3way:三向切分
Quick3wayBar:插入排序+三取樣切分+三向切分
QuickX:快速三向切分(插入排序 + 三取樣切分 + Tukey's ninther + Bentley-McIlroy 三向切分)
QuickKR:快速排序的最簡(jiǎn)單實(shí)現(xiàn)方式之一

Q:QuickBar 排序降序數(shù)組時(shí)饺藤,為什么報(bào)
java.lang.StackOverflowError 異常包斑?
*
A:因?yàn)檎{(diào)用層次過(guò)多
解決方案:排序之前調(diào)用 shuffle() 方法打亂數(shù)組即可,但是對(duì)效率有所影響涕俗。

總結(jié)

由上表可知:
①罗丰、在處理隨機(jī)數(shù)組的時(shí)候,QuickBar(插入排序+三取樣切分)速度較快
②再姑、在處理大量重復(fù)元素?cái)?shù)組的時(shí)候萌抵,Quick3wayBar(插入排序+三取樣切分+三向切分)速度最快。
③、綜合表現(xiàn)最好的是:QuickX(快速三向切分(插入排序 + 三取樣切分 + Tukey's ninther + Bentley-McIlroy 三向切分)

注意:編譯器默認(rèn)不適用 assert 檢測(cè)(但是junit測(cè)試中適用)绍填,所以要使用時(shí)要添加參數(shù)虛擬機(jī)啟動(dòng)參數(shù)-ea 具體添加過(guò)程霎桅,請(qǐng)參照eclipse 和 IDEA 設(shè)置虛擬機(jī)啟動(dòng)參數(shù)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市讨永,隨后出現(xiàn)的幾起案子滔驶,更是在濱河造成了極大的恐慌,老刑警劉巖住闯,帶你破解...
    沈念sama閱讀 211,948評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件瓜浸,死亡現(xiàn)場(chǎng)離奇詭異澳淑,居然都是意外死亡比原,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,371評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門(mén)杠巡,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)量窘,“玉大人,你說(shuō)我怎么就攤上這事氢拥“鐾” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 157,490評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵嫩海,是天一觀的道長(zhǎng)冬殃。 經(jīng)常有香客問(wèn)我,道長(zhǎng)叁怪,這世上最難降的妖魔是什么审葬? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,521評(píng)論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮奕谭,結(jié)果婚禮上涣觉,老公的妹妹穿的比我還像新娘。我一直安慰自己血柳,他們只是感情好官册,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,627評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著难捌,像睡著了一般膝宁。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上根吁,一...
    開(kāi)封第一講書(shū)人閱讀 49,842評(píng)論 1 290
  • 那天员淫,我揣著相機(jī)與錄音,去河邊找鬼婴栽。 笑死满粗,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的愚争。 我是一名探鬼主播映皆,決...
    沈念sama閱讀 38,997評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼挤聘,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了捅彻?” 一聲冷哼從身側(cè)響起组去,我...
    開(kāi)封第一講書(shū)人閱讀 37,741評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎步淹,沒(méi)想到半個(gè)月后从隆,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,203評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡缭裆,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,534評(píng)論 2 327
  • 正文 我和宋清朗相戀三年键闺,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片澈驼。...
    茶點(diǎn)故事閱讀 38,673評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡辛燥,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出缝其,到底是詐尸還是另有隱情挎塌,我是刑警寧澤,帶...
    沈念sama閱讀 34,339評(píng)論 4 330
  • 正文 年R本政府宣布内边,位于F島的核電站榴都,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏漠其。R本人自食惡果不足惜嘴高,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,955評(píng)論 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望辉懒。 院中可真熱鬧阳惹,春花似錦、人聲如沸眶俩。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,770評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)颠印。三九已至纲岭,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間线罕,已是汗流浹背止潮。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,000評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留钞楼,地道東北人喇闸。 一個(gè)月前我還...
    沈念sama閱讀 46,394評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親燃乍。 傳聞我的和親對(duì)象是個(gè)殘疾皇子唆樊,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,562評(píng)論 2 349

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