希尔排序是希尔(Donald Shell)于1959年提出的一种排序算法。
希尔排序也是一种插入排序,它是简单插入排序经过改进之后的一个更高效的版本,也称为缩小增量排序,同时该算法是冲破O(n2)的第一批算法之一。
基本思想:
希尔排序是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序;
随着增量逐渐减少,每组包含的关键词越来越多,
当增量减至1时,整个文件恰被分成一组,算法便终止。
希尔排序在数组中采用跳跃式分组的策略,通过某个增量将数组元素划分为若干组,
然后分组进行插入排序,随后逐步缩小增量,继续按组进行插入排序操作,直至增量为1。
希尔排序通过这种策略使得整个数组在初始阶段达到从宏观上看基本有序,小的基本在前,大的基本在后。
然后缩小增量,到增量为1时,其实多数情况下只需微调即可,不会涉及过多的数据移动。
希尔排序的基本步骤:
选择增量gap=length/2,缩小增量继续以gap = gap/2的方式,这种增量选择我们可以用一个序列来表示,{n/2,(n/2)/2...1},称为增量序列。(希尔排序的增量序列的选择与证明是个数学难题,我们选择的这个增量序列是比较常用的,也是希尔建议的增量,称为希尔增量,但其实这个增量序列不是最优的。)
此处我们做示例使用希尔增量。
在希尔排序的理解时,我们倾向于对于每一个分组,逐组进行处理,
但在代码实现中,我们可以不用这么按部就班地处理完一组再调转回来处理下一组(这样还得加个for循环去处理分组)
比如[5,4,3,2,1,0] ,首次增量设gap=length/2=3,则为3组[5,2] [4,1] [3,0],实现时不用循环按组处理,我们可以从第gap个元素开始,逐个跨组处理。
同时,在插入数据时,可以采用元素交换法寻找最终位置,也可以采用数组元素移动法寻觅。
1 #include<algorithm> 2 #include<iostream> 3 #include<cstdio> 4 #include<cstring> 5 #include<string> 6 #include<queue> 7 #include<cmath> 8 #define ll long long 9 #define DB double 10 #define mod 1000000007 11 #define inf 2147483600 12 using namespace std; 13 inline int read() 14 { 15 int x=0,w=1;char ch=getchar(); 16 while(ch<'0' || ch>'9'){if(ch=='-') w=-1;ch=getchar();} 17 while(ch>='0' && ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar(); 18 return x*w; 19 } 20 int n,a[1000000]; 21 void shell_sort(int len) 22 { 23 for(int gap=len/2;gap>=1;gap/=2) 24 for(int i=1;i<=gap;++i) 25 for(int j=i+gap;j<=n;j+=gap) 26 if(a[j]<a[j-gap]) 27 { 28 int tmp=a[j],k=j-gap; 29 while(k>=0 && a[k]>tmp) 30 { 31 a[k+gap]=a[k]; 32 k-=gap; 33 } 34 a[k+gap]=tmp; 35 } 36 } 37 int main() 38 { 39 n=read(); 40 for(int i=1;i<=n;++i) a[i]=read(); 41 shell_sort(n); 42 for(int i=1;i<=n;++i) printf("%d ",a[i]); 43 return 0; 44 }
想去海边玩耍。