希爾排序(最小增量排序)
基本思想:算法先將要排序的一組數按某個增量d(n/2,n爲要排序數的個數)分成若干組,每組中記錄的下標相差d.對每組中全部元素進行直接插入排序,然後再用一個較小的增量(d/2)對它進行分組,在每組中再進行直接插入排序。當增量減到1時,進行直接插入排序後,排序完成。
下面是關於算法的實現
public class ShellSort {
//希爾排序
public static void main(String[] args) {
int a[] = {5, 54, 6, 3, 78, 34, 12, 45, 56, 100};
double d1 = a.length;
int temp = 0;
while(true){
d1 = Math.ceil(d1/2); //ceil方法向下取整
int d = (int)d1; //獲得增量
for(int x = 0; x < d; x++) { //x作爲每一組的起始下標
for (int i = x + d; i < a.length; i += d) {
int j = i - d;
temp = a[i]; //a[i]是要插入的數
for(; j >= 0 && a[j] > temp ; j-=d) {
a[j+d] = a[j];
}
a[j+d] = temp;
}
}
if(d == 1) {
break;
}
}
for (int i = 0; i < a.length; i++ ) {
System.out.print(a[i]+" ");
}
}
}
希爾排序和直接插入排序算法其實特別相象,因爲是相當於通過增量的變化將原數組變成多組的的直接插入排序,在最後一次直接插入排序的時候,數組已經基本有序。
在實現的過程中出現兩個問題:
1、第17行 for(; j >= 0 && a[j] > temp ; j-=d) 這一句一開始被我寫成了 for(; j > 0 && a[j] > temp ; j-=d),出現的結果就是數組第一位數字不會被拿去比較,因爲直接短路的問題,後面循環體本次並不會執行。
2、發現可以有另一種實現方法。(區別主要在第17行到第21行),測試結果並無問題。
public class ShellSort2 {
//希爾排序
public static void main(String[] args) {
int a[] = {5, 54, 6, 3, 78, 34, 12, 45, 56, 100};
double d1 = a.length;
int temp = 0;
while(true){
d1 = Math.ceil(d1/2); //ceil方法向下取整
int d = (int)d1; //獲得增量
for(int x = 0; x < d; x++) { //x作爲每一組的起始下標
for (int i = x + d; i < a.length; i += d) {
int j = i - d;
temp = a[i]; //a[i]是要插入的數
for(; j >= 0 && a[j] > temp ; j-=d) {
a[j+d] = a[j];
a[j] = temp;
}
}
}
if(d == 1) {
break;
}
}
for (int i = 0; i < a.length; i++ ) {
System.out.print(a[i]+" ");
}
}
}
總的來說實現過程就是:1、定義增量
2、通過增量進行分組
3、對分好的組進行直接插入排序
4、改變增量值直到增量爲1時,進行直接插入排序。
時間複雜度:
希爾排序是按照不同步長對元素進行直接插入排序,當剛開始元素很無序的時候,步長最大,所以插入排序的元素個數很少,排序速度快;下一趟,步長變小,但是元素排列已經比之前相對有序了,而插入排序對於有序的序列效率很高,所以希爾排序的的時間複雜度會比直接插入排序的複雜度好一些。(以下時間複雜度是本人上網查詢的結果)
①平均時間複雜度是 O(n^1.3)
②最優時間複雜度是 O(n)
③最壞時間複雜度是 O(n^2)
空間複雜度:和直接插入排序一樣,只需要一個輔助存儲空間,所以空間複雜度爲O(1)
穩定性:希爾排序在增量不同時的分組排序,可能會導致相同的數的相對位置發生改變,是不穩定的。
適用情況:希爾排序的比較次數和移動次數都比直接插入排序要少,最壞情況下的比較次數是(n^1.5),n越大時,效果越明顯,所以適合初始記錄無序,n較大的情況。