排序算法-希爾排序(Shell Sort)

希爾排序法介紹

希爾排序法(Shell Sort)是D.L.Shell於1959年提出的一種排序算法,是直接插入排序法的更高效的改進版。在這之前的排序算法如冒泡排序簡單選擇排序直接插入排序等算法的的時間複雜度都爲O(n2)O(n^{2}),而希爾排序突破了這一時間複雜度。
【原理】
直接插入排序算法比冒泡排序和簡單選擇排序性能都要高,尤其在序列基本有序並且記錄數相對較少的情況,只需要簡單的幾個插入動作就能完成排序。

希爾排序的思路就是在插入排序算法的基礎上,創造插入排序算法的有利條件,將序列按照某個增量分成多個子序列進行插入排序,使整個序列變爲基本有序,並且由於按照增量分了子序列,所以每個子序列的記錄數變少了,增量和子序列長度成反比,增量從小於n的某個值每次遞減,子序列隨增量變小而變長。直到增量變爲1,使其所有記錄爲一個整體序列然後進行一次插入排序爲止。

什麼才叫基本有序呢?比如{2,1,4,3,5,6,8,7,9}可以說是基本有序,小的數字基本在序列的前部,不大不小的在中部,大的數字在後部。 {8,7,6,3,9,2,4,5,1}這樣的序列就不是基本有序,因爲1在序列的最後,9在中間,8在第一位,所以談不上是基本有序的。

【例子】
下面看個對關鍵字序列{8,7,1,9,3,6,4,5,2}進行希爾排序的步驟。
在這裏插入圖片描述

希爾排序法算法

public static void shellSort(Integer[] arr) {
    int increment = arr.length;
    do {
        increment = increment / 3 + 1;
        for (int i = increment; i < arr.length; i++) {
            if (arr[i-increment] > arr[i]){
                int minIdx = i;
                int compIdx = minIdx-increment; //需往右邊移動的關鍵字下標
                int minValue = arr[minIdx];
                while (compIdx >= 0 && arr[compIdx] > minValue) { //比較大小
                    arr[minIdx] = arr[compIdx]; //關鍵字右移
                    minIdx = compIdx;
                    compIdx = compIdx - increment;
                }
                arr[minIdx] = minValue; //插入關鍵字
            }
        }
    } while (increment > 1);
}

時間複雜度

希爾排序的時間複雜度依賴增量序列,增量的取值至今還是個難題,大量研究表明,當增量序列爲delta[k]=2tk+12^{t-k+1}-1(0\leqslantk\leqslanttlog2(n+1)\leqslant \left \lfloor log2(n+1) \right \rfloor) 時,可以獲得不錯的效率,其時間複雜度爲O(n3/2)O(n^{3/2}),要好於直接插入排序的O(n2)O(n^{2})

穩定性

由於按照增量跳躍式分成了子序列插入排序,所以相同值位置可能會被替換,所以希爾排序是不穩定的。

其他排序法的比較

以下分別使用簡單選擇排序法直接插入排序法和希爾排序法對10萬隨機關鍵字的排序耗時,從結果可以看出直接插入排序的執行時間比簡單選擇排序法快,而希爾排序法比直接插入排序法快了非常多隻用了38ms。

簡單選擇排序執行時間:8077ms
直接插入排序執行時間:4408ms
希爾排序執行時間:38ms
發佈了69 篇原創文章 · 獲贊 86 · 訪問量 27萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章