我們知道當乙個序列基本有序時,直接插入會變得很高效。因為此時只需少量的移動元素,操作集中在元素的比較上。基於這種想法,我們就試圖把乙個序列在進行直接插入前調整得盡量有序。這就是希爾排序(shell sort)的核心思路。(shell只是演算法發明者的名字,無特殊含義)
那到底該怎麼做呢?
希爾排序一反以前的做法,插入為何只在相鄰的元素之間進行,不相鄰的同樣可以進行。於是,希爾排序也被形象地稱為」跳著插「。
那應該隔幾個元素進行插入呢?
這就說到希爾排序的另乙個名字:縮小增量排序(diminishing increment sort)。實際上這個增量序列或者說步長序列是可以提前指定的。不同的序列可以極大地影響到演算法效率,至於最好的步長序列貌似還在研究。不過可以肯定的是最後的乙個步長一定是1。因為最後一次是直接插入。
先來看一種最簡單、也最常用的步長序列:n/2、n/2/2、... 1 (n是待排序的元素個數)。也是就說,初始步長是n/2,以後每次減半,直到步長為1。
利用這種步長序列,舉乙個例子:開始序列中加下劃線的字型表示每一趟待排序的數字。
原序列: 21 12 4 9 9 5 78 1 (n=8)
下標: 0 1 2 3 4 5 6 7
第一趟:步長step=4,0、4號元素直接插入排序
開始 21 12 4 9 9
5 78 1
結束 9
12 4 9 21
5 781
第二趟:步長step=2, 0、2、4、6號元素直接插入排序
開始9
12 4 9 21
5 781
結束 4 12 9 9 21 5 78 1
第三趟:步長step=1,0、1、2、3、4、5、6、7、8號元素直接插入排序(顯然這是整體直接插入排序)
開始 4129
921 5 781
結束 1 4 5 9 9 12 21 78
如何理解每一趟排序:
步長序列的長度決定了排序的趟數。
每一趟排序,並不是所有元素都參與。參與排序的只能是下標為 0、step、2*step...的元素。
插入排序時,採用何種策略。如直接插入、交換插入、折半插入、表插入或表折半插入,這可任意選擇。
最後一趟排序的步長一定是1。由第二點可知,最後一趟,全體元素都參與排序。
排序結果中紅色9出現在了黑色9的前面,表明希爾排序是不穩定的。
仔細觀察上述過程,一定可以理解上述四點。理解之後,就不難寫出**了。
下面給出這種排序的**:
void shellsort1(int a, int n) //希爾排序
}}
若是,看過插入排序:交換排序,相信很容易看懂上述**
。若是指定步長,**是這樣的:
void shellsort2(int a, int n, int step, int nn)
}}
其中step陣列代表步長序列,這裡的**與上乙個相比,只是用step[i]替換了step,其它並無變化。
測試走起……
插入排序小結:
一、什麼是插入排序?
把乙個元素插入到乙個已經有序的序列中去,就叫插入排序。
二、插入排序的複雜度(時間和空間)?
這個得看具體的插入策略。比如最簡單的直接插入。
空間複雜度 o(1)(只需乙個臨時變數)
時間複雜度
在最差的情況下,此時元素處於逆序。對於下標為i的元素,把它儲存在臨時變數中需移動一次,回填移動一次,由於逆序,前面的i個元素都得往後移動一次,共i次,顯然也需比較i次。
故共需移動 求和i+2(i=1...n-1)=(n-1)(n+4)/2
共需比較 求和i(i=1...n-1)=n(n-1)/2
以上兩者相加得 (n-1)(n+2)=o(n^2)
在最好的情況下,此時元素處於順序。對於下標為i的元素,把它儲存在臨時變數中需移動一次,回填移動一次,由於正序,前面的i個元素不需移動,且只需比較一次。
故共需移動 2(n-1)
共需比較 n-1
以上兩者相加得 3(n-1)=o(n)
若是計算平均時間複雜度,數學推理比較複雜,結論是 o(n^n)。
其它幾種插入策略,其時間複雜度更加難以推理,不過總體上都是o(n^n)的。快一點的如二路插入、希爾排序(n(logn)^2),量級上不會改變。
提高插入排序的效率,可以從兩個方面入手:減少比較次數、減少移動次數。
其中 二路插入是減少了移動次數,折半插入是減少了比較次數,表插入是用指標變化代替元素移動(因為指標變化代價比較低)。
若是對你有所幫助,頂乙個哦!
專欄目錄看這裡:
插入排序 希爾插入排序
本文借鑑於lsgo實驗室創始人馬老師 演算法 希爾插入排序 delta len nums 2 while delta 0 shell delta,nums delta delta 2return nums defshell delta,key for i in range delta,len key...
插入排序 希爾排序
希爾排序 先將整個待排序的記錄序列分割成為若干子串行分別進行直接插入排序,待整個序列中的記錄 基本有序 時,再對全體記錄進行依次直接插入排序。以n 10的乙個陣列49,38,65,97,26,13,27,49,55,4為例 第一次 gap 10 2 5 4938 6597 2613 2749554 ...
插入排序 希爾排序
希爾排序又叫縮小增量排序,希爾排序是1959 年由d.l.shell 提出來的,相對直接排序有較大的改進。基本思想 先將整個待排序的記錄序列分割成為若干子串行分別進行直接插入排序,待整個序列中的記錄 基本有序 時,再對全體記錄進行依次直接插入排序。基本操作如下 第一步 選擇乙個增量序列t1,t2,t...