排序演算法之插入排序(直接插入、希爾排序)
前言
一個好的排序演算法對於程式的優化會有很大的提升,雖然在許多語言的類庫中就存在了N種排序方法,但是隻有在瞭解了每一種排序演算法後才能更好的在實際中運用這些演算法。這裡我主要說明插入排序中的直接插入以及希爾排序的實現。
直接插入
直接插入排序是最簡單的排序演算法之一。對於直接插入排序,它始終維護著一個有序序列,在每一次插入操作時都將元素插入到這個有序序列對應的位置上。
對於一個待排序序列:3 1 4 8 6 5,插入排序的步驟如下:
該演算法也比較簡單:
public void insertionSort(T[] array){
int j = 0;
for(int i=1;i<array.length;i++){
T tmp = array[i];
for(j=i;j>0 && tmp.compareTo(array[j-1])<0;j--){
array[j] = array[j-1];
}
array[j] = tmp;
}
}
可以看出,該演算法從待排序的序列第二位開始始終維護著位置0到位置i為一個排過序的狀態。並且在進行元素交換過程中,採用移動法的方式,避免了多次的元素交換操作。
時間複雜度:O(N²)
空間複雜度:O(1)
希爾排序
希爾排序是希爾(Donald Shell)於1959年提出的一種排序演算法。希爾排序也是一種插入排序,它是簡單插入排序經過改進之後的一個更高效的版本,也稱為縮小增量排序,同時該演算法是衝破O(N²)的第一批演算法之一。
希爾排序是把記錄按下標的一定增量分組,對每組使用直接插入排序演算法排序;隨著增量逐漸減少,每組包含的關鍵詞越來越多,當增量減至1時,整個序列恰被分成一組,演算法便終止。
對於一個待排序序列:3 1 4 8 6 5 2 7,希爾排序的步驟如下:
希爾排序程式碼如下:
public void shellSort(T[] array){
int j;
for(int gap = array.length/2;gap>0;gap/=2){
for(int i=gap;i<array.length;i++){
T tmp = array[i];
for(j = i;j>=gap && tmp.compareTo(array[j-gap]) < 0;j -= gap){
array[j] = array[j - gap];
}
array[j] = tmp;
}
}
}
在希爾排序中,增量的選擇尤為重要,一個好的增量對於效能的提升有很大幫助,常用以及希爾建議的增量序列為:gap = (array.length)/2。
在程式碼的第4行,我們從增量大小的陣列下標位置開始向前進行插入排序。
時間複雜度:O(N²)
空間複雜度:O(1)
總結
對於直接插入排序以及希爾排序都是插入排序的一種,但是他們的最壞時間情形都會達到O(N²)。在對於元素的交換過程靈活的使用移動法,可以降低交換操作帶來的時間開銷。
更多瞭解,還請關注我的個人部落格:www.zhyocean.cn