排序算法二 -- 希爾排序

概述

希爾排序,也稱遞減增量排序算法,是插入排序的一種更高效的改進版本。但希爾排序是非穩定排序算法。

希爾排序是基於插入排序的以下兩點性質而提出改進方法的:

  • 插入排序在對幾乎已經排好序的數據操作時,效率高,即可以達到線性排序的效率;

這個結論很明顯,如果一個數組大部分元素都有序,那麼數組中的元素自然不需要頻繁地進行比較和交換。

  • 在元素數量較少的情況下,插入排序的工作量較小

這個結論更加顯而易見,插入排序的工作量和n的平方成正比,如果n比較小,那麼排序的工作量自然要小得多

也就是說:如果我們對數據做一些 “預處理”,使得原始數組的大部分元素變得有序,那麼我們再使用插入算法進行排序,那麼排序的效率將會大大提高。希爾排序正事基於這種思路實現的。

舉個栗子

這是我們現在拿到的原始數組:

第一輪,我們取總長度的一半,也就是4,作爲跨度,這樣兩兩一組,總共事4組:

接下來,我們讓每組元素進行獨立排序,排序方式用直接插入排序即可。由於每一組的元素數量很少,只有兩個,所以插入排序的工作量很少。每組排序完成後的數組如下:

這樣一來,僅僅經過幾次簡單的交換,數組整體的有序程度得到了顯著提高,使得後續再進行直接插入排序的工作量大大減少。這種做法,可以理解爲對原始數組的“粗略調整”。 但是這樣還不算完,我們可以進一步縮小分組跨度,重複上述工作。把跨度縮小爲原先的一半,也就是跨度爲2,重新對元素進行分組,一共兩組:

接下來,我們繼續讓每組元素進行獨立排序,排序方式用直接插入排序即可。每組排序完成後的數組如下:

最後,我們把分組跨度進一步減小,讓跨度爲1,也就等同於做直接插入排序。經過之前的一系列粗略調整,直接插入排序的工作量減少了很多,排序結果如下:

讓我們重新梳理一下分組排序的整個過程:

代碼實現:

    public static int[] sort(int[] arr) {
        if (arr.length < 2) {
            return arr;
        }
        int step = arr.length/2;
        for(;step>0;step/=2){
            for(int i=step;i<arr.length;i++){
                int temp = arr[i];
                int j=i;
                for(;j>=step && temp<arr[j-step];j-=step){
                    //符合條件往後移
                    arr[j] = arr[j-step];
                }
                arr[j] = temp;
            }
        }
        return arr;
    }

算法分析:

  • 時間複雜度:O(nlogn)
  • 空間複雜度:O(1)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章