希爾排序法介紹
希爾排序法(Shell Sort)是D.L.Shell於1959年提出的一種排序算法,是直接插入排序法的更高效的改進版。在這之前的排序算法如冒泡排序、簡單選擇排序、直接插入排序等算法的的時間複雜度都爲,而希爾排序突破了這一時間複雜度。
【原理】
直接插入排序算法比冒泡排序和簡單選擇排序性能都要高,尤其在序列基本有序並且記錄數相對較少的情況,只需要簡單的幾個插入動作就能完成排序。
希爾排序的思路就是在插入排序算法的基礎上,創造插入排序算法的有利條件,將序列按照某個增量分成多個子序列進行插入排序,使整個序列變爲基本有序,並且由於按照增量分了子序列,所以每個子序列的記錄數變少了,增量和子序列長度成反比,增量從小於n的某個值每次遞減,子序列隨增量變小而變長。直到增量變爲1,使其所有記錄爲一個整體序列然後進行一次插入排序爲止。
什麼才叫基本有序呢?比如{2,1,4,3,5,6,8,7,9}可以說是基本有序,小的數字基本在序列的前部,不大不小的在中部,大的數字在後部。 {8,7,6,3,9,2,4,5,1}這樣的序列就不是基本有序,因爲1在序列的最後,9在中間,8在第一位,所以談不上是基本有序的。
【例子】
下面看個對關鍵字序列{8,7,1,9,3,6,4,5,2}進行希爾排序的步驟。
希爾排序法算法
public static void shellSort(Integer[] arr) {
int increment = arr.length;
do {
increment = increment / 3 + 1;
for (int i = increment; i < arr.length; i++) {
if (arr[i-increment] > arr[i]){
int minIdx = i;
int compIdx = minIdx-increment; //需往右邊移動的關鍵字下標
int minValue = arr[minIdx];
while (compIdx >= 0 && arr[compIdx] > minValue) { //比較大小
arr[minIdx] = arr[compIdx]; //關鍵字右移
minIdx = compIdx;
compIdx = compIdx - increment;
}
arr[minIdx] = minValue; //插入關鍵字
}
}
} while (increment > 1);
}
時間複雜度
希爾排序的時間複雜度依賴增量序列,增量的取值至今還是個難題,大量研究表明,當增量序列爲delta[k]=-1(0kt) 時,可以獲得不錯的效率,其時間複雜度爲,要好於直接插入排序的。
穩定性
由於按照增量跳躍式分成了子序列插入排序,所以相同值位置可能會被替換,所以希爾排序是不穩定的。
其他排序法的比較
以下分別使用簡單選擇排序法、直接插入排序法和希爾排序法對10萬隨機關鍵字的排序耗時,從結果可以看出直接插入排序的執行時間比簡單選擇排序法快,而希爾排序法比直接插入排序法快了非常多隻用了38ms。
簡單選擇排序執行時間:8077ms
直接插入排序執行時間:4408ms
希爾排序執行時間:38ms