1. 程式人生 > >圖解排序演算法及實現——希爾排序 (Shell Sort)

圖解排序演算法及實現——希爾排序 (Shell Sort)

希爾排序(ShellSort)也稱增量遞減排序演算法,即跨多步版的InsertionSort,是InsertionSort基礎上的改進版。InsertionSort可以看作ShellSort中gap=1的特例。希爾排序是非穩定排序演算法。

希爾排序通過將全部元素分為幾個區域來提升插入排序的效能。這樣可以讓一個元素可以一次性地朝最終位置前進一大步。然後演算法再取越來越小的步長進行排序,演算法的最後一步就是普通的插入排序,但是到了這步,需排序的資料幾乎是已排好的了(此時插入排序較快)。

ShellSort的關鍵點在於gap序列的設計。

直觀理解1:以報數為例

每一輪報數,佇列中123123…(gap=3)地報數,所有報1的人組成一組,在原佇列中進行插入排序,其他組類似。
報數分為好幾輪,每輪gap值減小一次,每一輪都使序列漸進有序化,直到最後一輪gap=1,即為原始InsertionSort。從這個意義上說,ShellSort是加了預處理的InsertionSort。

直觀理解2: 將陣列列在一個表中,然後列排序

假設有這樣一組數

[ 13 14 94 33 82 25 59 94 65 23 45 27 73 25 39 10 ]

如果我們以步長為5開始進行排序,我們可以通過將這列表放在有5列的表中來更好地描述演算法,這樣他們就應該看起來是這樣:

13 14 94 33 82
25 59 94 65 23
45 27 73 25 39
10

然後我們對每進行排序:

10 14 73 25 23
13 27 94 33 39
25 59 94 65 82
45

將上述四行數字,依序接在一起時我們得到:[ 10 14 73 25 23 13 27 94 33 39 25 59 94 65 82 45 ].這時10已經移至正確位置了,然後再以3為步長進行排序:

10 14 73
25 23 13
27 94 33
39 25 59
94 65 82
45

排序之後變為:

10 14 13
25 23 33
27 25 59
39 65 73
45 94 82
94

最後以1步長進行排序(此時就是簡單的插入排序了)。

圖解

複雜度

ShellSort的複雜度分析非常複雜,不同gap序列的設計對應不同的複雜度。

最壞時間複雜度:根據步長序列的不同而不同。已知最好的: O(n (logn) ^2)
最優時間複雜度: O(n)
平均時間複雜度:根據步長序列的不同而不同。
最壞空間複雜度: O(n)

python實現

def ShellSort(arr):

    n = len(arr)

    # 初始步長
    gap = n // 2

    while gap >=1 :
        for i in range(gap, n):
            # 每個步長進行插入排序
            temp = arr[i]
            # 插入排序
            j = i
            while j >= gap:
                if arr[j - gap] > temp:
                    arr[j] = arr[j - gap]
                    j -= gap
                else:
                    break
            arr[j] = temp

        # 得到新的步長
        gap = gap // 2

步長序列

步長的選擇是希爾排序的重要部分。只要最終步長為1任何步長序列都可以工作。演算法最開始以一定的步長進行排序。然後會繼續以一定步長進行排序,最終演算法以步長為1進行排序。

Donald Shell最初建議步長選擇為 n/2 並且對步長取半直到步長達到1。雖然這樣取可以比 O(n^2)類的演算法更好,但這樣仍然有減少平均時間和最差時間的餘地。

已知的最好步長序列是由Sedgewick提出的(1, 5, 19, 41, 109,…)。這項研究也表明“比較在希爾排序中是最主要的操作,而不是交換。”用這樣步長序列的希爾排序比插入排序要快,甚至在小陣列中比快速排序和堆排序還快,但是在涉及大量資料時希爾排序還是比快速排序慢。

另一個在大陣列中表現優異的步長序列是(斐波那契數列除去0和1將剩餘的數以黃金分割槽比的兩倍的冪進行運算得到的數列):(1, 9, 34, 182, 836, 4025, 19001, 90358, 428481, 2034035, 9651787, 45806244, 217378076, 1031612713,…)