1. 原理
希爾排序是希爾(Donald Shell)於1959年提出的一種排序算法。希爾排序也是一種插入排序,它是簡單插入排序經過改進之後的一個更高效的版本,也稱爲縮小增量排序,同時該算法是衝破O(n2)的第一批算法之一。它與插入排序的不同之處在於,它會優先比較距離較遠的元素。
希爾排序是把記錄按下表的一定增量分組,對每組使用直接插入排序算法排序;隨着增量逐漸減少,每組包含的關鍵詞越來越多,當增量減至1時,整個文件恰被分成一組,算法便終止。
2. 算法描述
希爾排序的基本步驟:
選擇增量 :gap=length/2,縮小增量:gap = gap/2
增量序列:用序列表示增量選擇,{n/2, (n/2)/2, …, 1}
希爾排序的增量序列的選擇與證明是個數學難題,我們選擇的這個增量序列是比較常用的,也是希爾建議的增量,稱爲希爾增量,但其實這個增量序列不是最優的。此處我們做示例使用希爾增量。
先將整個待排序的記錄序列分割成爲若干子序列分別進行直接插入排序,具體算法描述:
選擇一個增量序列t1,t2,…,tk,其中ti>tj,tk=1;
按增量序列個數k,對序列進行k趟排序;
每趟排序,根據對應的增量ti,將待排序列分割成若干長度爲m 的子序列,分別對各子表進行直接插入排序;
僅增量因子爲1 時,整個序列作爲一個表來處理,表長度即爲整個序列的長度。
3. 算法分析
排序方式:in-place
時間複雜度:
- 最佳情況:T(n) = O(n)
- 最壞情況:T(n) = O(n2)
- 平均情況:T(n) =O(n1.3)
空間複雜度:O(1)
4. 動圖演示
5. 代碼
public static void main(String[] args) {
long[] arrs = RandomArr.createLongArr(21, 0, 200);
long[] arrs2 = Arrays.copyOf(arrs, arrs.length);
Arrays.stream(arrs).forEach(l -> {
System.out.print(l + " ");
});
System.out.println();
shellSort(arrs);
Arrays.stream(arrs).forEach(l -> {
System.out.print(l + " ");
});
System.out.println();
Arrays.stream(arrs2).sorted().forEach(l -> {
System.out.print(l + " ");
});
}
public static void shellSort(long[] arrs) {
long tmp;
int index;
int gap = arrs.length / 2;
while (gap > 0) {
for (int i = gap; i < arrs.length; i++) {
tmp = arrs[i];
for (index = i - gap; index >= 0 && arrs[index] > tmp; ) {
arrs[index + gap] = arrs[index];
index -= gap;
}
arrs[index + gap] = tmp;
}
gap /= 2;
}
}