希爾排序就這麼簡單

1、希爾排序介紹

來源百度百科:html

希爾排序(Shell's Sort)是插入排序的一種又稱「縮小增量排序」(Diminishing Increment Sort),是直接插入排序算法的一種更高效的改進版本。希爾排序是非穩定排序算法。該方法因D.L.Shell於1959年提出而得名。

從上面咱們很容易看出來,它是插入排序的高級版java

回顧一下插入排序:算法

  • 將數據插入到已有序的數列中shell

    • 排序前:將每一個元素當作有序的數列
    • 第一趟排序後:獲得一個有序數列,其大小爲2
    • 第二趟排序後:獲得一個有序數列,其大小爲3
    • 第三趟排序後:獲得一個有序數列,其大小爲4
    • ........每一趟插入排序,均可以將一個無序值插入一個有序數列,直至所有值有序
  • 若是給出的數組足夠亂的話,那麼插入排序所耗費的時間是O(n^2)

既然希爾排序是插入排序的高級版,那它作了哪些優化呢??讓咱們來看看:數組

  • 希爾排序在排序前:將一個序列分紅了好幾個序列
  • 在第一趟排序時:將這幾個序列作插入排序。排序後,部分較大的數字日後靠,部分較小的數字往前靠
  • 在第二趟排序時:將這個序列又分了好幾個序列作插入排序(但比第一次分的數要少,ps:若是第一次分5個,第二次可能就2個了)。排序後,部分較大的數字日後靠,部分較小的數字往前靠
  • ................
  • 在第n趟排序時:將這個序列又分了好幾個序列(直到剩下一個序列),從宏觀上看,此序列就基本是有序的了。這時就用簡單插入排序將數列直至已序

從直觀上看希爾排序:微信

  • 就是把數列進行分組(不停使用插入排序),直至從宏觀上看起來有序,最後插入排序起來就容易了(無須屢次移位或交換)。

那麼,上面那裏說了將一個序列分紅好幾個序列,那麼到底怎麼分呢?好比有10個元素的序列,分紅幾個才合適?每次縮減又是多少呢?優化

從專業的角度上講,將一個序列分紅好幾個序列,用一個數來表示:那個數稱爲增量。顯然的是,增量是不斷遞減的(直到增量爲1)spa

每每的:若是一個數列有10個元素,咱們第一趟的增量是5,第二趟的增量是2,第三趟的增量是1。若是一個數列有18個嚴肅,咱們第一趟的增量是9,第二趟的增量是4,第三趟的增量是2,第四趟的增量是1.net

很明顯咱們能夠用一個序列來表示增量:{n/2,(n/2)/2...1}每次增量都/2code

2、希爾排序體驗

如今咱們有一個數組,該數組有6個元素

int[] arrays = {2, 5, 1, 3, 4, 6};

排序前:

  • 將該數組當作三個(arrays.length/2)數組,分別是:{2,3},{5,4},{1,6}

第一趟排序:

  • 對三個數組分別進行插入排序,所以咱們三個數組獲得的結果爲{2,3},{4,5},{1,6}

    • 此時數組是這樣子的:{2, 4, 1, 3, 5, 6}

第二趟排序:

  • 增量減小了,上面增量是3,此時增量應該爲1了,所以把{2, 4, 1, 3, 5, 6}當作一個數組(從宏觀上是有序的了),對其進行插入排序,直至有序

可能我舉的例子不夠好(沒看到很好的效果),咱們來看看網上的圖片,加深一下希爾排序的過程:


PS:圖片來源網上(侵刪)

3、希爾排序代碼實現

public static void shellSort(int[] arrays) {


        //增量每次都/2
        for (int step = arrays.length / 2; step > 0; step /= 2) {

            //從增量那組開始進行插入排序,直至完畢
            for (int i = step; i < arrays.length; i++) {

                int j = i;
                int temp = arrays[j];

                // j - step 就是表明與它同組隔壁的元素
                while (j - step >= 0 && arrays[j - step] > temp) {
                    arrays[j] = arrays[j - step];
                    j = j - step;
                }
                arrays[j] = temp;
            }
        }


    }

咱們發現希爾排序代碼其實很是簡單(相比對堆排序),理解起來也不難,就用增量來將數組進行分隔,直到增量爲1。底層乾的仍是插入排序乾的活~

4、最後

參考資料:

若是文章有錯的地方歡迎指正,你們互相交流。習慣在微信看技術文章,想要獲取更多的Java資源的同窗,能夠 關注微信公衆號:Java3y
相關文章
相關標籤/搜索