八大排序———希爾排序
希爾排序(Shell's sort)是插入排序的一種 又稱為“縮小增量排序”(Diminishing Increment Sort),是直接插入排序演算法的一種更高效的改進版本。希爾排序是不穩定的排序演算法。
希爾排序是把記錄按下標的一定增量分組,對每組使用直接插入排序演算法排序;隨著增量的逐漸減少,每組包含的關鍵字越來越多,當增量減少至1時,整個檔案恰被分為一組,演算法終止。
希爾排序是基於插入排序的一下兩點性質而提出改進方法的:
1.插入排序在對幾乎已經排好序的資料操作時,效率高,既可以達到線性排序的效率。
2.但插入排序一般來說是低效的,因為插入排序每次只能將資料移動一位。
一:基本思想
先取一個小於n的整數d1作為第一個增量,把檔案的全部記錄分組。所有距離為d1的倍數的記錄放在同一個組中。先在各組中進行直接插入排序;然後取第二個增量d2<d1重複上述的分組和排序,直至所取的增量d = 1,即所有的記錄放在同一組中進行直接插入排序為止。
實質:分組插入方法
比較相隔較遠距離(稱為增量)的數,使得移動時能夠跨越多個元素,則進行一次比較就可能消除多個元素的交換。
一般的初次取序列的一半為增量,以後每次減半,直到增量為1。
二:演示過程
三:程式碼解析
#include<iostream> using namespace std; template<typename T> void shellinsert(T arr[],int len,int grp)//O(n) { int i = grp; int j = 0; T tmp = T(); for(i=grp;i<len;++i) { tmp = arr[i]; for(j = i-grp;j>=0;j-=grp) { if(arr[j]>tmp) { arr[j+grp] = arr[j]; } else break; } arr[j+grp] = tmp; } } template<typename T> void shell(T arr[],int len) { for(int div = len/2;div>0;div/=2)//時間複雜度為O(log n) shellinsert(arr,len,div); } int main() { int arr[] = {15,48,67,9,45,13,16,9,99,13}; int len = sizeof(arr)/sizeof(arr[0]); shell1(arr,len); for(int i= 0;i<len;++i) { cout<<arr[i]<<" "; } cout<<endl; return 0; }
四:穩定性分析
由於多次插入排序,我們知道一次插入排序是穩定的,不會改變相同元素的相對順序,但在不同的插入排序過程中,相同的元素可能在各自插入排序中移動,最後其穩定性就會被打亂,所以shell排序是不穩定的。
五:時間複雜度
演算法的平均複雜度為 O(n^1.3),演算法的最壞的時間複雜度為O(n^2),最好的時間複雜度為O(n),空間複雜度為O(1)。
六:演算法分析
不需要大量的輔助空間,希爾排序是基於插入排序的一種演算法,在此演算法之上增加了新的特性,提高了效率。希爾排序的時間複雜度與增量序列的選取有關,例如希爾增量的時間複雜度為O(n^2),而Hibbard增量的希爾排序的時間複雜度為O(n^1.5),當資料量相當大的時間,其演算法的效率不如快排快,因此中等大小的資料量適用於希爾排序,希爾排序在最壞和平均的情況下執行效率差不多,而快速排序的最壞和平均的情況下其相差比較大,所以,幾乎任何排序工作在開始時都可以用希爾排序,如果在實際中,其速度不能滿足我們的要求我們在使用快排。
shell演算法的效能與所選取的分組長度序列有關。