希尔排序的基本思想:选定第一个增量d1(一般取d1=n/2),从第一条记录起,把全部记录按此值进行分组,所有相距为d1的记录为一组,然后在各组中进行直接插入排序,然后缩小间隔(一般采用希尔提出的取法:di+1 = di/2 ),使用新的间距重复上述分组和排序过程;如此反复,直到增量d=1,即所有数字在同一组内排序。
如对记录数n=8的序列进行希尔排序(同颜色为一组,每组进行希尔排序):
(1)d1=n/2 = 8/2 = 4 共分成4组: 60 71 49 11 82 49 3 66
(2)d2=d1/2 = 4/2 = 2 共分成2组: 60 49 3 11 82 71 49 66
(3)d3=d2/2 = 2/2 = 1 共分成1组: 3 11 49 49 60 66 82 71
算法思路(通过三层循环来实现 ):
(1)外循环以各种不同的间距距离d进行排序,直到d=1;
(2)第二重循环是在某一个d值下对各组进行排序,若在某个d值下发生记录的交换,则须继续第三重循环,直至各组内均无记录的交换为止,即各组内已经完成了排序任务。
(3)第三重循环从第一个记录开始,以某个d值为间距进行组内比较,若有逆序,进行交换。
以下是严格按照定义来写的代码(t[]为待排序数组,n为数组长度):
void xeinsert0(int t[],int n)
{
int i,j,d,temp;
for(d=n/2;d>0;d/=2)//增量,取di=n/2,di+1=di/2
for(i=0;i<d;i++)//共分成d组数据,分别进行直接插入排序
{
for(j=i+d;j<n;j+=d)//对第i组数据进行插入排序
{
if(t[j]<t[j-d])//当待插入元素 < 已排好序列的最后一个元素,则需查找正确位置插入,否则插入到已排好的序列最后(即不需移动)
{
temp = t[j];
j = j-d;
while(j>=0&&temp<t[j])//查找正确插入的位置
{
t[j+d] = t[j];
j-=d;
}
t[j+d] = temp;//插入正确的位置
}
}
}
}
void xeinsert(int t[],int n)
{
int i,j,d,temp;
for(d=n/2;d>0;d/=2)//增量
{
for(i=d;i<n;i++)//插入排序
{
if(t[i]<t[i-d]){
temp = t[i];
j = i-d;
while(j>=0&&t[j]>temp)
{
t[j+d] = t[j];
j-=d;
}
t[j+d] = temp;
}
}
}
}
测试函数:
//打印数组
void myPrint(int t[],int n)
{
for(int i=0;i<n;i++)
{
printf("%d\t",t[i]);
}
printf("\n");
}
void main()
{
int t[] = {60,71,49,11,82,49,3,66};
xeinsert(t,8);
myPrint(t,8);
}