Java算法(3):希爾排序

希爾排序

1.定義:

(1)基於插入排序的排序算法

(2)原因:對於大規模亂序數組插入排序很慢,因爲它只會交換相鄰的元素,因此元素只能一點一點地從數組的一端移動到另一端。例如:若值最小的元素正好在數組的盡頭,要將它挪到正確的位置就要要進行 數組的長度-1 次移動。

(3)希爾排序時先將任意間隔爲h的元素都進行插入排序,同時,間隔h是一個遞增序列中的一個值,且h按照遞增序列遞減,即這個h會隨着每一次循環排序結束後越來越小,因此,排序的精度也會越來越高。

(4)希爾排序的思想是使數組中任意間隔爲h的元素都是有序的。這樣的數組稱爲h有序數組。一個h有序數組就是h個互相獨立的有序數組編織在一起組成的一個數組。

(5)希爾排序更高效的原因是它權衡了子數組的規模和有序性。排序之初,各個子數組都很短,排序之後子數組都是部分有序的,這兩種情況都很適合插入排序。

(6)到現在爲止,沒有任何一個遞增序列被發現是效率最高的,因此,透徹理解希爾排序的性能至今仍然是一個挑戰。但我們還是知曉它的性能絕對是比一些初級排序高的。

(7)總結:博主認爲希爾排序其實是對數組進行多次插入排序,前面的插入排序行爲都是爲了使得最後的那一次插入排序變的更加容易,即更適合插入排序。

 

2.代碼剖析:

假設:數組a,長度N,下標 i,間隔爲h,遞增序列3 * n + 1,因此間隔h = 3 * n + 1(n=0,1,2,3... ; h=1,4,13,40,121,264...)

(1)首先,我們要獲得第一個間隔h,這個h既要在遞增序列中,又要滿足剛好大於N/3(這裏的3是我們本文使用的遞增序列的常數因子3

(2)獲得了第一個間隔h後,我們通過間隔h,將數組分成多個大小爲h的數組,分別進行插入排序。排序完成後,第一次循環結束。

(3)接着,在一次循環結束後,這時我們的間隔h應該要變的更小以使排序精確度增加。因此,可以直接h = h/3 就可以得出下一個間隔h,並用這個h再將數組分割成多個大小爲h的數組,分別進行插入排序。

(4)如此以往,直到h = 1 時,進行最後一次排序,其實此時就相當於對數組進行插入排序(但由於前面已經對其做了處理,所以這次的插入排序速度那是相當的快滴)。

(5)注:爲了使得h最後能夠變成1,因此遞增序列最後需要加個1來保證。

 

3.圖解:

 

4.按照這個思路,寫出代碼:

    /**
     * 希爾排序
     * @param array
     */
    //遞增序列的常數因子
    private static final int MULTIPLE = 3;

    public static void shellSort(int[] array) {
        //將a[]按升序排序
        int N = array.length;
        int h = 1;
        int t;
        //獲得第一個間隔h
        while (h < N / MULTIPLE) {
            //這裏加一是爲了能夠最後可以使得h變爲1
            h = MULTIPLE * h + 1;
        }
        while (h >= 1) {
            //將數組變爲h有序
            for (int i = h; i < N; i++) {
                //對a[i],a[i-h],a[i-2*h],a[i-3*h]..進行插入排序
                for (int j = i; j >= h && array[j] < array[j - h]; j -= h) {
                    t = array[j];
                    array[j] = array[j - h];
                    array[j - h] = t;
                }
            }
            //一次循環結束,更新間隔h
            h = h / MULTIPLE;
        }
    }

 

5.算法優劣分析:

(1)毋庸置疑,效率肯定比插入排序高,並且數組越大,優勢越大。

(2)遞增序列的選擇會影響希爾排序的效率,本文使用的遞增序列應該可以對付大部分情況。

(3)對於中等大小的數組,使用希爾排序時可以接收的,它不僅代碼量很小,而且不需要使用額外的內存空間。雖然有更加高效的其他算法,但除了數組非常非常打之外,它們的速度可能只會比希爾排序快兩倍,關鍵是更復雜。

(4)因此,如果需要解決一個排序問題而又沒有系統排序函數可用,可以先用希爾排序,然後再考慮是否應該將它替換爲更加複雜的排序算法。

 

6.資料引用:

《算法Algorithms(第4版)》 p162~p165

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