先取一個小於n的整數d1作爲第一個增量,把文件的全部記錄分組。所有距離爲d1的倍數的記錄放在同一個組中。先在各組內進行直接插入排序;然後,取第二個增量d2<d1重複上述的分組和排序,直至所取的增量 =1( < …<d2<d1),即所有記錄放在同一組中進行直接插入排序爲止。
該方法實質上是一種分組插入方法
比較相隔較遠距離(稱爲增量)的數,使得數移動時能跨過多個元素,則進行一次比較就可能消除多個元素交換。D.L.shell於1959年在以他名字命名的排序算法中實現了這一思想。算法先將要排序的一組數按某個增量d分成若干組,每組中記錄的下標相差d.對每組中全部元素進行排序,然後再用一個較小的增量對它進行,在每組中再進行排序。當增量減到1時,整個要排序的數被分成一組,排序完成。
一般的初次取序列的一半爲增量,以後每次減半,直到增量爲1。
假設待排序文件有10個記錄,其關鍵字分別是:
592,401,874,141,348,72,911,887,820,283。
增量序列的取值依次爲:
5,2,1
操作步驟:
(1)相隔距離爲gap= 5 的元素組成一組,可以分爲 5 組,按照直接插入排序的方法對每個組進行排序。
(2)再上次的 gap 縮小一半,即 gap= gap / 2 = 2 (取整數)。這樣每相隔距離爲 2 的元素組成一組,可以分爲 2 組,按照直接插入排序的方法對每個組進行排序。
(3)在第三趟排序中,再次把 gap 縮小一半,即gap = gap / 2 = 1。 這樣相隔距離爲 1 的元素組成一組,即只有一組,按照直接插入排序的方法對每個組進行排序。此時,排序已經結束。
算法實現
public static void shellSort(int a[]) {
intd= a.length;//gap的值
while (true){
d = d/ 2;//每次都將gap的值減半
for (int x = 0; x< d; x++) {//對於gap所分的每一個組
for (int i = x+ d; i < a.length; i= i + d) { //進行插入排序
int temp= a[i];
intj;
for (j= i - d; j>= 0 && a[j] > temp;j = j - d){
a[j+ d] = a[j];
}
a[j+ d] = temp;
}
}
if (d== 1) {//gap==1,跳出循環
break;
}
}
}
最壞情況下時間複雜度:O(N*logN),最壞的情況下和平均情況下差不多。
在排序過程中,需要一個臨時變量存儲要插入的值,所以空間複雜度爲1。
希爾排序中相等數據可能會交換位置,所以希爾排序是不穩定的算法。