1. 程式人生 > >數據結構和算法之排序六:希爾排序

數據結構和算法之排序六:希爾排序

style 發展 思想 希爾 發現 冒泡 縮小 pre mage

  經過前面五篇排序方法的介紹,我們了解到了遞歸思想以及分而治之的歸並和快速排序,當然也涉及到了比較簡單易懂的數據值傳遞冒泡,選擇,以及插入排序。可以說每一種排序方式都各有千秋,都適合在不同的環境下進行使用,但是我們有時會不會思考一個問題,那就是我們在學習插入排序的時候的主題思想是將每一個數據取出來,然後和後邊的前邊的數據逐一進行比較,那麽,我們是不是要進行N-1次的循環,或者說我們是不是要進行大約N的平方次比較,我們知道,在進行值的交換和比較是非常消耗時間的,那麽是不是違背了我們算法的發展。有沒有更好的方式去進行解決,在數據量浩大的時候,我們能否對插入進行修改,到達一個理想的結果。那麽,我們將要介紹的希爾排序應運而生,如果你對插入排序不是很了解,那麽我建議去看完插入排序再來看希爾排序,在我的認知裏,希爾排序或者可以說成是插入排序的升級版,他用到的核心思想還是插入排序。我們前邊就提到了分而治之的思想,在數據量浩大的時候,我們可不可以提取出其中的一部分作為一個小組,然後有N個小組,我們隊這些小組進行排序,那麽總體的數組我們可不可以看成是一個間斷有序的數組,然後我們在進行整體的插入的時候我們是不是能避免很多次重復的比較,或者說是數據交換。所以,如果你看到這的時候,應該能夠理解希爾排序,其實就是將一個整體單元化,進行預處理,然後再進行整體的處理,這和歸並排序是不是有點不謀而合,分而治之。說話不能理解,那我們直接上圖:

      技術分享圖片

  我們可以看到上圖訴說的思想,我們選取的單元大小與我們的步長有關,也就是說我們的步長有多上種,那麽我們就對這個數組進行過幾次預處理,在這樣的情況下,始終我們的步長會得到1,那麽也就是說我們在進行最後的插入排序的時候是不是進行過必要的處理,那麽我們將在最後;排序時使用最少的數據交換和比較。可以這麽說,希爾排序為什麽在處理大量數據是會比插入排序優秀,那也是縮小數據量以及讓數據間斷性的有序,減少其比較和交換數據的次數。舉一個見到的例子,我們很不幸運,最後一個數據是最小的值,如果我們繼續使用插入排序是不是意味著我們y要進行N-1次的比較,消耗的時間對於我們來說有一點不能接受,如果我們按照上圖所示,進行一定步長的比較,讓間斷性有序,是不是會減少大量的比較步驟,代碼奉上:

 1 public static void shellSort(int arr[]){
 2       int n = arr.length;
 3       //選擇步長
 4       for(int gap = n / 2;gap >= 1;gap /= 2){
 5            //選擇組別
 6            for(int i = 0;i < gap;i++){
 7                 //需要進行插入的key值
 8                 for(int j = i + gap;j < n;j += gap){
 9                       //
對該值與前一個值進行比較,是否需要交換 10 if(arr[j] < arr[j - gap]){ 11 int key = arr[j]; 12 int k = j - gap; 13 while(k >= 0 && key < arr[k]){ 14 //進行值交換 15 arr[k + gap] = arr[k]; 16 } 17 //選取出來的key值歸位 18 arr[k + gap] = key; 19 } 20 } 21 } 22 } 23 }

  我們從以上的代碼能夠更直觀的感受到,其實希爾排序就是先把一個整體分成無數個單元片段,根據步長,然後對這些單元進行排序,達到間斷性有序的效果,最後在進行整體的插入排序,我們可以看到,在進行第一個for循環,我們其實就是想要獲取一個步長,步長是在不斷縮短的,那就意味著整體的分組在不斷減少,直到為一結束。然後我們在第二個循環選取出不同的分組,其實這是我的理解,也可以說是根據不同的起始值加上步長也就獲取了一定量的數據作為一個組別的數據。在第三個循環我們就對這個小組的數據進行正常的插入排序,希爾排序就是一個具有一定步長的插入排序,我們可以這麽理解!

  需要註意的問題:

      一:關於希爾排序步長的選擇問題:

          說實話,我對於這個問題確實有點不太了解,不太方便做出相應的解釋,但是在我看的算法第四版書籍以及數據結構和算法中對於這個問題的闡述說的是選擇N/3作為步長,但是大部分人都選擇N/2作為步長,其實我們發現一個完美的步長能夠幫助我們很多,但是很遺憾,我給出不了這個解釋,有興趣可以去看一下其它專業的解釋。步長的選取和希爾排序的效率息息相關,我們知道這一點足矣。

      二:關於希爾排序的代碼優化:

          如果我們可以用心留意,看見很多人對於希爾排序都有著濃厚的興趣,進行嘗試性的不斷優化,但是,我想說的是,這樣導致很多地方的希爾已經變形,拋離了主旨思想,其實我們在學習一種算法的時候在自己水平不夠的情況下掌握最基準的解釋翻譯過來的代碼即可,我上邊的代碼或許看起來比較復雜,但是應該是最容易理解的一種理解方式。抓住兩個關鍵問題,對步長變化的控制,對於用步長為基準的單元片段進行插入排序的方法,這就是最基礎的希爾排序,如果以後我的水平提升,再和大家討論關於希爾問題的步長問題。

  

數據結構和算法之排序六:希爾排序