希爾排序原理
希爾排序(shell sort)這個排序方法又稱為縮小增量排序,是1959年D·L·Shell提出來的。
該方法的基本思想是:設待排序元素序列有n個元素,首先取一個整數increment(小於n)作為間隔將全部元素分為increment個子序列,所有距離為increment的元素放在同一個子序列中,在每一個子序列中分別實行直接插入排序。然后縮小間隔increment,重復上述子序列划分和排序工作。直到最后取increment=1,將所有元素放在同一個子序列中排序為止。
由於開始時,increment的取值較大,每個子序列中的元素較少,排序速度較快,到排序后期increment取值逐漸變小,子序列中元素個數逐漸增多,但由於前面工作的基礎,大多數元素已經基本有序,所以排序速度仍然很快。
希爾排序流程
1、給出一個待排序的數據列:
2、第一趟取increment的方法是:n/3向下取整+1=3(關於increment的取法之后會有介紹)。將整個數據列划分為間隔為3的3個子序列,然后對每一個子序列執行直接插入排序,相當於對整個序列執行了部分排序調整。圖解如下:
3、第二趟將間隔increment= increment/3向下取整+1=2,將整個元素序列划分為2個間隔為2的子序列,分別進行排序。圖解如下:
4、第3趟把間隔縮小為increment= increment/3向下取整+1=1,當增量為1的時候,實際上就是把整個數列作為一個子序列進行插入排序,圖解如下:
5、直到increment=1時,就是對整個數列做最后一次調整,因為前面的序列調整已經使得整個序列部分有序,所以最后一次調整也變得十分輕松,這也是希爾排序性能優越的體現。
希爾排序實現代碼:
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的取法
增量increment的取法有各種方案。最初shell提出取increment=n/2向下取整,increment=increment/2向下取整,直到increment=1。但由於直到最后一步,在奇數位置的元素才會與偶數位置的元素進行比較,這樣使用這個序列的效率會很低。后來Knuth提出取increment=n/3向下取整+1.還有人提出都取奇數為好,也有人提出increment互質為好。應用不同的序列會使希爾排序算法的性能有很大的差異。
希爾排序復雜度分析
對於希爾排序其增量increment的選擇非常關鍵,最燃至今其怎樣選擇還是一個數學難題,但是通過大量研究表明,當增量序列為dlta[k]= -1(0≤k≤t≤ (n+1))時,可以獲得不錯的效率,其時間復雜度為O( ),要好於直接排序的O( ),需要注意的是增量序列的最后一個增量值必須等於1才行。另外由於記錄是跳躍性的移動,希爾排序並不是一種穩定的排序算法。
本文參考:https://blog.csdn.net/weixin_37818081/article/details/79202115