希爾排序算法

    希爾排序Shell Sort)是 D.L.Shell 於1959 年提出來的一種排序算法,在這之前排序算法的時間複雜度基本都是O(n2)的,希爾排序算法是突破這個時間複雜度的第一批算法之一。
    直接插入排序,應該說,它的效率在某些時候是很高的,比如,我們的記錄本身就是基本有序的,我們只需要少量的插入操作,就可以完成整個記錄集的排序工作,此時直接插入很高效。還有就是記錄數比較少時,直接插入的優勢也比較明顯。可問題在於,兩個條件本身就過於苛刻,現實中記錄少或者基本有序都屬於特殊情況。
    不過別急,有條件當然是好,條件不存在,我們創造條件,也是可以去做的。於是科學家希爾研究出了一種排序,對直接插入排序改進後可以增加效率的方法。
    如何讓待排序的記錄個數較少呢?很容易想到的就是將原本有大量記錄數的記錄進行分組。分割成若干個子序列,此時每個子序列待排序的記錄個數就比較少了。然後在這些子序列內分別進行直接插入排序,當整個序列都基本有序時,注意只是基本有序時,再對全體記錄進行一次直接插入排序。


    在介紹算法之前,先定義一個數組。

   #define LEN 11

   int number[LEN] = {0, 25, 19, 6, 58, 34, 10, 7, 98, 160, 0};  

   // number[0]是作爲哨兵用的,並不屬於待排序數列,待排序數列爲number[1]...number[LEN]。

   具體算法如下:

void ShellSort(int *s, int n)
{
    int i, j;
    int d = n - 1;        // d爲增量, 初始值爲待排列數據個數              
    while(d > 1) {
        d = d / 2;        // 增量變化
        for(i = d + 1; i != n; i++)
        {  
            // 直接插入排序
            if(s[i] < s[i-d])  // 將一組中相鄰的的兩個數比較  
            {
                s[0] = s[i];
                for(j = i - d; j > 0 && s[0] < s[j]; j -= d)
                    s[j+d] = s[j];
                s[j+d] = s[0];
            }
        }
    }
}

     

      1)第一次的增量d = 5, 需要比較的數據和排序的數據是s[1]和s[6]、s[2]和s[7].....s[5]和s[10]。       整個希爾排序的算法過程如下如所示:

79ab1624f331df484d088dea.jpg
      2)本次排序的結果如下圖:

           第二次的增量爲2,需要排序的是s[1] s[3] s[5] s[7] s[9]、s[2] s[4] s[6] s[8] s[10]。

           對每一組需要排序的數列,使用的是直接插入法。

   eb2a341386ff7f6adc5401f5.jpg

     3) 本次排序的結果如下圖:

           第三次的增量爲1,需要排序的是s[1] s[2] s[3] s[4] s[5] s[6] s[7] s[8] s[9] s[10]。

           對這一組需要排序的數列,使用直接插入法。

f3512ec84e2bbf5e7e3e6ff7.jpg

      4) 當d=1 是進行最後一次排序。最終結果如下:

cdfffc4f5d40817faec3abf2.jpg

  希爾排序的具體思路就是這樣。


   通過這段代碼的剖析,相信大家有些明白,希爾排序的關鍵並不是隨便的分組後各自排序,而是將相隔某個“增量”的記錄組成一個子序列,實現跳躍式的移動,使得排序的效率提高。
     這裏“增量”的選取就非常關鍵了。我們在代碼中第7行,是用d = d / 2; 的方式選取增量的,可究竟應該選取什麼樣的增量纔是最好,目前還是一個數學難題,迄今爲止還沒有人找到一種最好的增量序列。不過大量的研究表明,當增量序列爲dlta[k]=2t-k+1-1(0≤k≤t≤log2(n+1))時,可以獲得不錯的效率,其時間複雜度爲O(n3/2),要好於直接排序的O(n2)。需要注意的是,增量序列的最後一個增量值必須等於1才行。另外由於記錄是跳躍式的移動,希爾排序並不是一種穩定的排序算法。
     不管怎麼說,希爾排序算法的發明,使得我們終於突破了慢速排序的時代(超越了時間複雜度爲O(n2)),之後,相應的更爲高效的排序算法也就相繼出現了。


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