其餘排序方法:選擇排序、冒泡排序、歸併排序、快速排序、插入排序、希爾排序html
希爾排序大概就是,選一組遞減的整數做爲增量序列。最小的增量必須爲1:\(D_M>D_{M-1}>...>D_1=1\)python
看圖更容易理解吧:
(借用一下慕課的浙大數據結構課件。由於課件本來是ppt,而我只有pdf,因此顏色沒有上齊,請將就將就emmm)
shell
希爾排序快不快主要取決於咱們怎麼取增量序列,原始希爾排序的取法就是:\(D_M=\lfloor N/2 \rfloor, D_k=\lfloor D_{k+1}/2 \rfloor\)
此增量序列也成爲Shell增量序列
原始希爾排序最壞的時間複雜度爲\(O(n^2)\)數組
# 原始希爾排序 # 增量序列爲D(M)=N/2, D(k)=D(k+1)/2 向下取整 def shellSort(arr): size = len(arr) # 正整數右移一位至關於除以2且向下取整 step = size >> 1 while step > 0: for i in range(step, size): j = i tmp = arr[j] while j >= step: if tmp < arr[j - step]: arr[j] = arr[j - step] j -= step else: break arr[j] = tmp step = step >> 1
希爾排序的優化主要是針對增量序列的優化。
增量序列若是取得很差,效率比直接插入排序還要低,下面舉個例子(直接借用課件了):數據結構
在這個例子裏,前幾個增量沒有起到任何做用(只起到了拖延時間的做用哈哈)。
因此有人就發現了,若是增量之間不互質的話,那有些狀況就無論用了。app
因而有些大佬們就整出了下面這些增量序列:Hibbard增量序列、Knuth增量序列、Sedgewick增量序列等等
下面主要介紹Hibbard增量序列和Sedgewick增量序列函數
Hibbard增量序列的取法爲\(D_k=2^k-1\):{1, 3, 7, 15, 31, 63, 127, 255, 511, 1023, 2047, 4095, 8191...}
最壞時間複雜度爲\(O(N^{3/2})\);平均時間複雜度約爲\(O(N^{5/4})\)性能
先來個Hibbard增量序列的獲取代碼:測試
# Hibbard增量序列 # D(i)=2^i−1,i>0 def getHibbardStepArr(n): i = 1 arr = [] while True: tmp = (1 << i) - 1 if tmp <= n: arr.append(tmp) else: break i += 1 return arr
排序代碼稍微修改一下就行:大數據
# 希爾排序(Hibbard增量序列) def shellSort(arr): size = len(arr) # 獲取Hibbard增量序列 stepArr = getHibbardStepArr(size) # 由於要倒着使用序列裏的增量,因此這裏用了reversed for step in reversed(stepArr): for i in range(step, size): j = i tmp = arr[j] while j >= step: if tmp < arr[j - step]: arr[j] = arr[j - step] j -= step else: break arr[j] = tmp
至於爲何要用python內置函數reversed()
,而不用其它方法,是由於reversed()
返回的是迭代器,佔用內存少,效率比較高。
若是先使用stepArr.reverse()
,再用range(len(arr))
的話,效率會比較低;
並且實測reversed
也比range(len(arr) - 1, -1, -1)
效率高,故使用reversed()
;
還有就是先stepArr.sort(reverse=True)
,再用range(len(arr))
,一樣效率低。
這幾種方法比較的測試代碼在這裏,有興趣的朋友能夠看看:Python列表倒序輸出及其效率
Sedgewick增量序列的取法爲\(D=9*4^i-9*2^i+1\)或\(4^i-3*2^i+1\):{1, 5, 19, 41, 109, 209, 505, 929, 2161...}
最壞時間複雜度爲\(O(N^{4/3})\);平均時間複雜度約爲\(O(N^{7/6})\)
Sedgewick增量序列的獲取代碼:
# Sedgewick增量序列 # D=9*4^i-9*2^i+1 或 4^(i+2)-3*2^(i+2)+1 , i>=0 # 稍微變一下形:D=9*(2^(2i)-2^i)+1 或 2^(2i+4)-3*2^(i+2)+1 , i>=0 def getSedgewickStepArr(n): i = 0 arr = [] while True: tmp = 9 * ((1 << 2 * i) - (1 << i)) + 1 if tmp <= n: arr.append(tmp) tmp = (1 << 2 * i + 4) - 3 * (1 << i + 2) + 1 if tmp <= n: arr.append(tmp) else: break i += 1 return arr
排序代碼稍微修改一下就行:
# 希爾排序(Sedgewick增量序列) def shellSort(arr): size = len(arr) # 獲取Sedgewick增量序列 stepArr = getSedgewickStepArr(size) for step in reversed(stepArr): for i in range(step, size): j = i tmp = arr[j] while j >= step: if tmp < arr[j - step]: arr[j] = arr[j - step] j -= step else: break arr[j] = tmp