希尔排序(Shellsort)简介

来源:互联网 发布:云影源码1llo 编辑:程序博客网 时间:2024/06/03 11:18

希尔排序

希尔排序(Shell Sort)是D.L.Shell于1959年提出的一种排序算法,在这之前排序算法的时间复杂度都是O(n^2)级别的,希尔排序算法是突破这个时间复杂度的第一批算法之一


可以说,希尔排序是直接插入排序的一种改进。对于直接插入排序,它的效率在有些时候是很高的,比如记录本身是无序度很低的,我们只需要少量的插入操作,就可以完成整个记录的排序工作。基于此,希尔研究出了一种排序方法,对直接插入排序进行改进,创造“基本有序”的条件来增加效率。


所谓的基本有序,就是小的关键字基本在前面,大的基本在后面,不大不小的基本在中间。





算法代码示例

void ShellSort(SqList *L){int i,j;int increment=L->length;do{increment=increment/3+1;for(i=increment+1;i<=L->length;++i)        {if(L->r[i]<L->r[i-increment])                        {L->r[0]=L->r[i];for(j=i-increment;j>0&&L->r[0]<L->r[j];j-=increment)L->r[j+increment]=L->r[j];L->r[j+increment]=L->r[0];}}}        while(increment>1);}


算法分析

1.程序开始运行,此时我们传入的Sqlist参数的值为length=9,r[10]={0,9,1,5,8,3,7,4,6,2}。 如下图所示



2.第4行,变量increment即为增量,这里初始值等于排序的记录数


3. 第5~19行是一个do循环 ,它的终止条件是increment不大于1时,也就是增量为1时循环停止(增量必须有为1的过程,否则可能排序失败


4.第7行,缩小increment。这里采用/3+1的方法


5.第8~17行是一个for循环,i从4+1=5开始到9结束


6.第10行判断大小,满足条件的话就交换一些位置的值(前面放到后面,中间距离差值为increment)



7.循环继续,i=6,L.r[6]=7>L.r[i-increment]=L.r[2]=1,因此不交换



8.  循环继续,i=7,L.r[7]=4<L.r[i-increment]=L.r[3]=5,交换两者数据



9.循环继续,i=8,L.r[8]=6<L.r[i-increment]=L.r[4]=8,交换两者数据



10.循环继续,i=9,L.r[9]=2<L.r[i-increment]=L.r[5]=9,交换数据。注意,第13~14行是循环,此时由于满足循环条件,还要继续比较L.r[5]与L.r[1]的大小,因为2<3,所以还要交换L.r[5]与L.r[1]的数据


经过第一轮循环后,数组的排序结果如下图所示。可以发现,通过这样的一次排序,整个序列已经基本有序了。这就是Shell sort的精华所在,它将关键字较小的记录,不是一步一步地往前挪动,而是跳跃式地前移,从而使得每一次循环后更加有序。


11. 在完成第一轮do循环之后,此时由于increment=4>1 因此我们需要继续do循环。第7行得到increment=2。第8~17行for循环,i从2+1=3开始到9结束。当i=3、4时不需交换,当i=5时,需要交换数据



12.此后,i=6、7、8、9均不用交换



13.再次完成一轮do循环,increment=2>1,再次do循环,第7行得到increment=2/3+1=1,此时就是最后一轮了。尽管第8~17行for循环,i从2到9,但由于当前序列已经基本有序,交换数据情况较少,效率较高



14.最终完成排序过程,如下图




复杂度分析

我们能感觉到shell sort的关键在于increment,增量的选择至今仍是一个难题,还没有最好的increment

大量研究表明当增量序列为时,可以获得不错的效率,其时间复杂度大约为O(n^1.5)。需要注意的是增量序列的最后一个增量必须为1


另外希尔排序是一种不稳定的排序算法。



Wikipedia:https://en.wikipedia.org/wiki/Shellsort


原创粉丝点击