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

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

      

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

 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做爲步長,其實咱們發現一個完美的步長可以幫助咱們不少,可是很遺憾,我給出不了這個解釋,有興趣能夠去看一下其它專業的解釋。步長的選取和希爾排序的效率息息相關,咱們知道這一點足矣。學習

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

          若是咱們能夠用心留意,看見不少人對於希爾排序都有着濃厚的興趣,進行嘗試性的不斷優化,可是,我想說的是,這樣致使不少地方的希爾已經變形,拋離了主旨思想,其實咱們在學習一種算法的時候在本身水平不夠的狀況下掌握最基準的解釋翻譯過來的代碼便可,我上邊的代碼或許看起來比較複雜,可是應該是最容易理解的一種理解方式。抓住兩個關鍵問題,對步長變化的控制,對於用步長爲基準的單元片斷進行插入排序的方法,這就是最基礎的希爾排序,若是之後個人水平提高,再和你們討論關於希爾問題的步長問題。spa

相關文章
相關標籤/搜索