視頻動畫 | 什麼是希爾排序?

點擊藍色「五分鐘學算法」關注我喲

加個「星標」,天天中午 12:15,一起學算法

作者 | 我脫下短袖

來源 | 算無遺策

希爾排序屬性

 

上篇寫的直接插入排序算法時間複雜度是O(n^2),如果要令此排序算法的時間複雜度要低於O(n^2),必須是「遠距離的元素交換」使得這組元素能提高有序的程度,然後進行直接插入排序的時候可以減少交換的工作量。

 

那通過什麼減少交換的工作量呢?希爾排序可以解決這個問題。

 

希爾排序在做直接插入排序之前,希望可以對原整個待排序列進行預處理,目的是爲了最後一步直接插入排序的時候可以減少交換次數,同時也減少時間上的消耗。

 

假定數組初始狀態:5,1,9,3,7,4,8,6,2

 

然後設定初始增量是gap=length/2 =9/2=4,意味着兩個元素之間比較和交換的距離都是4(隔着3個元素),然後也會被分成4組,【5,7,2】,【1,4】,【9,8】,【3,6】。

 

對這5組分別進行直接插入排序,在代碼的進行中,它們都是穿插的進行直接插入排序,待會在下面視頻動畫可以看到。

 

對4組進行完排序的時候接着逐步縮小增量,gap=4/2=2,說明兩個元素待會比較和交換的距離都是2,被分爲兩組,對着兩組也進行排序。

 

最後增量縮小爲1,這時候就是純正的直接插入排序了,因爲在前面進行了預處理,使得這整個序列進行了「粗略調整」,在做最後一步的直接插入排序的時候,如果待排序列明顯有序的話,就真正減少了交換的次數,也真正減少了時間上的消耗。

 

(在做動畫的過程中,中間出錯了一個元素交換,已修正,播放的時候中間部分動作會有點趕)。

 

視頻動畫:希爾排序交換法

Code

Result

 

初始狀態 [5, 1, 9, 3, 7, 4, 8, 6, 2]

4增量

交換 [5, 1, 8, 3, 7, 4, 9, 6, 2]

交換 [5, 1, 8, 3, 2, 4, 9, 6, 7]

交換 [2, 1, 8, 3, 5, 4, 9, 6, 7]

2增量

交換 [2, 1, 5, 3, 8, 4, 9, 6, 7]

交換 [2, 1, 5, 3, 8, 4, 7, 6, 9]

交換 [2, 1, 5, 3, 7, 4, 8, 6, 9]

1增量

交換 [1, 2, 5, 3, 7, 4, 8, 6, 9]

交換 [1, 2, 3, 5, 7, 4, 8, 6, 9]

交換 [1, 2, 3, 5, 4, 7, 8, 6, 9]

交換 [1, 2, 3, 4, 5, 7, 8, 6, 9]

交換 [1, 2, 3, 4, 5, 7, 6, 8, 9]

交換 [1, 2, 3, 4, 5, 6, 7, 8, 9]

 

我們爲了減少交換的次數,也可以繼續優化,採用移動法的方式也可以減少交換的時間消耗。

 

視頻動畫:希爾排序移動法

Code

 

 

Result

初始狀態 [5, 1, 9, 3, 7, 4, 8, 6, 2]

4增量

移動 [5, 1, 9, 3, 7, 4, 9, 6, 2]

移動 [5, 1, 8, 3, 7, 4, 9, 6, 7]

移動 [5, 1, 8, 3, 5, 4, 9, 6, 7]

2增量

移動 [2, 1, 8, 3, 8, 4, 9, 6, 7]

移動 [2, 1, 5, 3, 8, 4, 9, 6, 9]

移動 [2, 1, 5, 3, 8, 4, 8, 6, 9]

1增量

移動 [2, 2, 5, 3, 7, 4, 8, 6, 9]

移動 [1, 2, 5, 5, 7, 4, 8, 6, 9]

移動 [1, 2, 3, 5, 7, 7, 8, 6, 9]

移動 [1, 2, 3, 5, 5, 7, 8, 6, 9]

移動 [1, 2, 3, 4, 5, 7, 8, 8, 9]

移動 [1, 2, 3, 4, 5, 7, 7, 8, 9]

 

希爾增量(Shell增量序列)

 

上面的過程使用的{4,2,1}被稱爲希爾排序的增量,是逐步折半縮小增量的過程。Shell增量序列的遞推公式爲:

 

 

Shell增量序列的最壞時間複雜度爲 O(n^2)。

 

希爾排序的增量序列的選擇有很多種,關於那些增量序列的選擇證明和過程比較複雜,就不糾結了。本文即將給出兩個案例,它們都可能比Shell增量序列要好:Hibbard增量序列和Sedgewick增量序列。

 

Hibbard增量序列

 

Hibbard增量序列的通項公式爲:

 

 

Hibbard增量序列的遞推公式爲:

 

 

Hibbard 增量序列的最壞時間複雜度爲 O(n^(3/2));平均時間複雜度約爲 O(n^(5/4))。

 

Code

 

 

得到的,是比length小的最大初始增量。然後在下面代碼中只修改獲取初始增量的一步就好了,縮減方式和希爾增量一樣的,不做修改。

 

 

Sedgewick增量序列

 

Sedgewick增量序列的通項公式爲:

 

 

Sedgewick 增量序列的最壞時間複雜度爲 O(n^(4/3));平均時間複雜度約爲 O(n^(7/6))。

 

初次看這段公式的時候突然有點看不懂了,仔細看看原來是中間還有個小逗號,意思是這兩個增量序列的並查集,拿到比length小的最大值(初始增量)就可以了。

 

Code

 

這過程有點複雜,因爲存在兩段公式的關係,不能直接求得初始增量就可以了,還要考慮到縮小增量的下一個數應該用哪個公式。採用的方式創建動態數組,在while(增量<lenght)條件下不斷的加入新的元素作爲增量,直到比length大才作罷,還要去除掉最有一個已經比length大的增量。

 

 

上面解釋一下「<<」的運算符,它是轉化成二進制然後左移幾位的算法,例如9<<1,9轉化成二進制1001,然後左移一位,後面補零得10010,轉化爲十進制就是18,相當於9*2=18。

 

再例如7<<2,7轉化爲二進制111,左移兩位成11100,轉化爲十進制就是32,相當於7*(2^2)=32。

 

」>>」運算符也是同樣的,相當於除以2的幾次方。

 

下面代碼獲取初始增量的也要修改,增量縮減方式也要相應的修改,然後其它的代碼不變。

 

 

本文介紹了希爾排序的基本思想、優化以及代碼的實現,包括後面兩個增量序列的選擇。增列序列的選擇方式對希爾排序也很重要,直接影響到希爾排序的性能。

 

有熱門推薦????

1.程序員我們就必須承認:這個世界上,有很多問題,就是無解的

2.【GitHub我在 GitHub 上看到了一個喪心病狂的開源項目!

3.【算法動畫:七分鐘理解什麼是KMP算法

4.【數據結構十大經典排序算法動畫與解析,看我就夠了!