減治算法: 插入排序和希爾排序(詳解)

減治法:

減治(decrease-and-conquer)法利用了一個問題給定實例的解和同樣問題較小實例的解之間的某種關係解決問題。我們既可以自頂向下(導致遞歸),也可以自底向上(導致迭代)地運用該關係解決問題。

插入排序:

想象一下整理撲克牌的情景,我們將每一張牌插入到其他已經有序的牌中的適當位置。在數組中,爲了給要插入的元素騰出空間,我們需要將其餘所有元素在插入之前都向右移動一位,這種算法叫做插入排序
插入排序所需的時間取決於輸入中元素的初始順序。對一個很大的基本有序的數組進行插入排序會比對一個隨機順序的數組進行插入排序快得多。

    public static void insertion(Integer[] r) {
        int N = r.length;
        int j;
        for (int i = 1; i < N; i++) {
            int p = r[i];
            for (j = i; j > 0 && r[j - 1] > p; j--)
                r[j] = r[j - 1];// 將正確位置之後的元素都向後移動一格。
            r[j] = p;//將第i個元素插入到已經有序的數組
        }
    }

算法分析:
插入排序的基本操作是比較,比較次數顯然依賴於特定的輸入。在最壞情況下比較次數和插入排序相同,大約爲(N^2)/2。最好的情況下是N-1次,不過這沒特別大的意義,對我們比較重要的是對隨機序列的數組排序的性能。對隨機數組,插入排序的平均比較次數是最壞情況下的一半,大約爲(N^2)/4

改良分析:
插入排序性能的瓶頸在於:每次都要移動索引位置到正確位置之間所有的元素,如果最小的元素在數組最右側,那我們就需要移動整個數組。這顯然是十分不划算的,所以有人發明了一個改進的算法,希爾排序(shellsort)。

希爾排序:

希爾排序是衝破二次時間屏障的第一批算法之一。不過直到它最初被發現的若干年後才證明了它的亞二次時間屆。希爾排序使用一個序列h1,h2,……,ht, 叫做增量序列(increment sequence)。只要h1 = 1,任何增量序列都是可以的,不過有些序列比另外一些序列更好。

該方法的基本思想是:先將整個待排元素序列分割成若干個子序列(由相隔某個“增量”的元素組成的)分別進行直接插入排序,然後依次縮減增量再進行排序,待整個序列中的元素基本有序(增量足夠小)時,再對全體元素進行一次直接插入排序。因爲直接插入排序在元素基本有序的情況下(接近最好情況),效率是很高的,因此希爾排序在時間效率上比前兩種方法有較大提高。

希爾排序

    public static void shell(Integer[] r) {
        int N = r.length;
        int h = 1;
        while (h < N / 3)
            h = 3 * h + 1;//計算增量序列的最大值:1,4,13,40,121,364,1093
        while (h >= 1) {
            for (int i = h; i < N; i++) {//i初始化h以避免數組越界
                for (int j = i; j >= h && r[j] < r[j - h]; j -= h) {
                    int temp = r[j];
                    r[j] = r[j - h];
                    r[j - h] = temp;
                }
            }
            h /= 3;//取增量序列的前一個值
        }
    }

算法分析:
研究希爾排序的性能非常複雜,上述代碼的最差情況的時間複雜度爲O(N^3/2)
原始的算法實現(希爾增量)在最壞的情況下需要進行O(n^2)的比較和交換。V. Pratt的書對算法進行了少量修改,可以使得性能提升至O(n log^2 n)。這比最好的比較算法的O(n log n)要差一些。

增量序列:
增量序列的選擇是希爾排序的一個重要部分。只要最終步長爲1任何步長序列都可以工作。算法最開始以一定的步長進行排序。然後會繼續以一定步長進行排序,最終算法以步長爲1進行排序。當步長爲1時,算法變爲插入排序,這就保證了數據一定會被排序。
希爾排序的增量序列


總結:

插入排序:平均性能比最差情況下快一倍,以及對基本有序數組的優異表現,使得插入排序優於選擇排序和冒泡排序。

希爾排序:希爾排序的性能在實踐中是完全可以接受的,編程簡單的特點使他領先於很多其他的排序算法,並且它不需要額外的內存空間

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章