[4] 算法之路 - 插入排序之Shell間隔與Sedgewick間隔
題目
插入排序法由未排序的後半部前端取出一個值。插入已排序前半部的適當位置。概念簡單但速度不快。
排序要加快的基本原則之中的一個:
是讓後一次的排序進行時,盡量利用前一次排序後的結果,以加快排序的速度,Shell排序法即是基於此一概念來改良插入排序法。
解法
Shell排序法最初是D.L Shell於1959所提出,如果要排序的元素有n個,則每次進行插入排序時並非全部的元素同一時候進行時,而是取一段間隔。
Shell排序算法 – n/2間隔
Shell首先將間隔設定為n/2,然後跳躍進行插入排序,再來將間隔n/4。跳躍進行排序動作,再來間隔設定為n/8、n/16,直到間隔為
Shell排序算法 – Sedgewick間隔
將間隔設定為n / 2是D.L Shell最初所提出,在教科書中使用這個間隔比較好說明,然而Shell排序法的關鍵在於間隔的選定。比如Sedgewick證明選用下面的間隔能夠加 快Shell排序法的速度:
e.g 對於一個長度為10000的整型數組,
Swedge[0]=10000, Swedge[1]=2537, Swedge[2]=653, Swedge[4]=48,Swedge[5]=15…Swedge[8]=1
採用Swedge間隔須要叠代8次 (Swedge[0] 不使用)
而用普通Shell間隔須要叠代13次
Comsh [0]=10000, Comsh [1]=5000, Comshe[2]=2500, Comsh[4]=625,…..Comshell[8]=39, Comshell[13]=1
後來還有人證明有其他的間隔選定法能夠將Shell排序法的速度再加快;另外Shell排序法的概念也能夠用來改良氣泡排序法。
SourceCodes
n/2間隔與Sedgewick間隔的 Shell排序
int DLShellSort(int a[],int lens) { for(int gap=lens/2;gap>0;gap/=2) { InsertionSortWithGap(a,lens,gap); } return 0; } // 4*((2^j)^2)+3*(2^j)+1<=n // j= log(((-3+sqrt(16*lens-7.0))/8))/log(2.0) int SedgewickShellSort(int a[],int lens) { int sdwindex= (int)log(((-3+sqrt(16*lens-7.0))/8))/log(2.0); int sdwpr=(int)pow(2,(double)sdwindex); int sdwpr2=sdwpr/2; while(true) { int sdwgap=4*sdwpr2*sdwpr2+3*sdwpr2+1; InsertionSortWithGap(a,lens,sdwgap); sdwpr2/=2; if(sdwpr2<=1)break; } return 0; }
// 插入排序 使用指定間隔的 int InsertionSortWithGap(int a[],int lens,int gap) { int k,tmp; // 控制插入層 for(int m=0;m<gap;m++) { for(int i=gap+m;i<lens;i+=gap) { int j=i-gap; tmp=a[i]; for(k=j;k>=0;k-=gap) { if(tmp<a[k]) a[k+gap]=a[k]; else break; } if(i!=(k+gap))a[k+gap]=tmp; } } return 0; }
[4] 算法之路 - 插入排序之Shell間隔與Sedgewick間隔