希爾排序(shell sort)這個排序方法又稱爲縮小增量排序,是1959年D·L·Shell提出來的。
該方法的基本思想是:設待排序元素序列有n個元素,首先取一個整數increment(小於n)做爲間隔將所有元素分爲increment個子序列,全部距離爲increment的元素放在同一個子序列中,在每個子序列中分別實行直接插入排序。而後縮小間隔increment,重複上述子序列劃分和排序工做。直到最後取increment=1,將全部元素放在同一個子序列中排序爲止。
因爲開始時,increment的取值較大,每一個子序列中的元素較少,排序速度較快,到排序後期increment取值逐漸變小,子序列中元素個數逐漸增多,但因爲前面工做的基礎,大多數元素已經基本有序,因此排序速度仍然很快。java
一、給出一個待排序的數據列:
二、第一趟取increment的方法是:n/3向下取整+1=3(關於increment的取法以後會有介紹)。將整個數據列劃分爲間隔爲3的3個子序列,而後對每個子序列執行直接插入排序,至關於對整個序列執行了部分排序調整。圖解以下:
三、第二趟將間隔increment= increment/3向下取整+1=2,將整個元素序列劃分爲2個間隔爲2的子序列,分別進行排序。圖解以下:
四、第3趟把間隔縮小爲increment= increment/3向下取整+1=1,當增量爲1的時候,實際上就是把整個數列做爲一個子序列進行插入排序,圖解以下:
五、直到increment=1時,就是對整個數列作最後一次調整,由於前面的序列調整已經使得整個序列部分有序,因此最後一次調整也變得十分輕鬆,這也是希爾排序性能優越的體現。算法
希爾排序實現代碼:shell
public class ShellSort { public void shellSort(int[] elem) { int i, j; int increment = elem.length; do { increment = increment / 3 + 1; for (i = increment + 1; i < elem.length; i++) { if(elem[i] < elem[i - increment]) { elem[0] = elem[i]; for (j = i - increment; j > 0 && elem[0] < elem[j]; j -= increment) { elem[j + increment] = elem[j]; } elem[j + increment] = elem[0]; } } } while(increment > 1); } public static void main(String[] args) { int[] elem = {0, 9, 1, 5, 8, 3, 7, 4, 6, 2}; ShellSort s = new ShellSort(); s.shellSort(elem); for (int i = 1; i < elem.length; i++) { System.out.print(elem[i] + ", "); } } }
增量increment的取法有各類方案。最初shell提出取increment=n/2向下取整,increment=increment/2向下取整,直到increment=1。但因爲直到最後一步,在奇數位置的元素纔會與偶數位置的元素進行比較,這樣使用這個序列的效率會很低。後來Knuth提出取increment=n/3向下取整+1.還有人提出都取奇數爲好,也有人提出increment互質爲好。應用不一樣的序列會使希爾排序算法的性能有很大的差別。性能
對於希爾排序其增量increment的選擇很是關鍵,最燃至今其怎樣選擇仍是一個數學難題,可是經過大量研究代表,當增量序列爲dlta[k]=2t−k+12^{t-k+1}2t−k+1-1(0≤k≤t≤log2log_2log2(n+1))時,能夠得到不錯的效率,其時間複雜度爲O(n3/2n^{3/2}n3/2),要好於直接排序的O(n2n^2n2),須要注意的是增量序列的最後一個增量值必須等於1才行。另外因爲記錄是跳躍性的移動,希爾排序並非一種穩定的排序算法。spa