您的位置:首页 > 运维架构 > Shell

Shell(希尔)排序的分析和比较

2013-01-07 18:18 260 查看
此文章建立在最希尔排序稍微有些了解。

这里有一个Shell排序的算法演示

/*******	Shell Sort	       			********/
/*******	Data:  2012.1.7 			********/
/*******	Author:  1 i f e			********/
#include<stdio.h>
int main()
{
int data[100],temp,i,j,n;
n=100;
for(i=1;i<n;i++)
{
temp =data[i];
for(j=i;j>0&&data[j]<data[j-1];j--)//这里有一点,小技巧就是说,插入排序建立在,已经排好的序列之上,所以那么既然data[j]<data[j-1]不成立,说明这个说这个数已经大于了前面所有已排序好的数
{
data[j]=data[j-1];
}
data[i]=temp;
}
}


这是基本的插入排序,它的时间复杂度最坏是O(n!),但是开销花在数据移动上。

插入排序在什么时候会很快?当整个数组大部分(这个大部分,是对于全局而言)都已经排序好了,插入排序秩序进行添加只需移动较少的数据即可完成。

插入排序对于后期数据的维护性非常好。



Shell排序是分组的插入排序。分组有局部分组,还有就是间隔step实现全局分组



如果是局部分组即1~step,step~2*step,。。。。这对于插入排序是毫无意义的,假如要实现从小到大排序,第一组就有可能出现了这个数组的最大的数,想通过最后一组,可能出现来了这个数组中的最小值。所以不可以提升性能。



而间隔性的step分组即{0,step,2*step。。。}为一组。{1,1+step,1+2*step。。。}为一组。实现的全局的大致排序,对插入排序的下一次,提供了基础。

void ShellSort(int *data,int n)
{
int i,k,j=-1,step,temp;     //关于这里为何为j=-1,因为在调试的时候发现,while循环执行,会先将j+1。
step=n/2;
while(step>0)     //这里则是进行对step判断,循环step>0
{
while(++j<step)     //这里是分了多组的插入排序,循环j<step
{
for(i=j+step;i<n;i+=step)     //这里则是一组具体的插入排序,循环i<n
{
temp=data[i];
for(k=i;k>=j+step&&data[k]<data[k-step];k-=step)     //对照上面的插入排序,是似曾相识的。区别在这里k>=j+step,因为,分为多组,每一组以j开头,所以对比下发现,因为上面的插入排序只有一组,所以省略了而已。因而对于上面而言,规范的书写是i=(0+step)
data[k]=data[k-step];
data[k]=temp;
}
}
j=-1;
step=step/2;
}


对于希尔排序,假如n=8,step=4完成后可能没有完成功能即可能相距4的还没有排序好。就进行了step=2的排序。这里可能会造成错误。

例如:44  55  12  42  94  18  6  67

第一次(即while(step>0)完成一趟循环):44   18 
 6   42  94   55  12
 67          step=4(同一种颜色为一组)




第二次:6 18  44  42  12
 55  94  67          step=2一种颜色一组,可以看出粉颜色这一组,部分插入排序没做好,44还在12之前,所以还要进行step=2的一次排序)

因此,对于这种解决方法

有两种可以解决:1、设一个标志位,如果发生过移动,就再重复一遍,直至不发生移动 。

2、也是我要采用的方法

void ShellSort(int *data,int n)
{
int i,k,j=-1,step,temp; //关于这里为何为j=-1,因为在调试的时候发现,while循环执行,会先将j+1。
step=n/2;
while(step>0) //这里则是进行对step判断,循环step>0
{
while(++j<step) //这里是分了多组的插入排序,循环j<step
{
for(i=j+step;i<n;i+=step) //这里则是一组具体的插入排序,循环i<n
{
temp=data[i];
for(k=i;k>=j+step&&temp<data[k-step];k-=step) //对照上面的插入排序,是似曾相识的。区别在这里k>=j+step,因为,分为多组,每一组以j开头,所以对比下发现,因为上面的插入排序只有一组,所以省略了而已。因而对于上面而言,规范的书写是i=(0+step)
data[k]=data[k-step];
data[k]=temp;
}
}
j=-1;
step=step/2;
}

for(k=i;k>=j+step&&temp<data[k-step];k-=step)
注意加红的部分,很简单的更改
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息