基本思想:
想将整个待排序的记录序列分割成为若干个子序列分别进行直接插入排序,带整个序列中的记录“基本有序”时,在对全体记录进行依次直接插入排序
操作方法:
1、选择一个增量序列t1,t2,.......tk,其中ti > tk,tk = 1;
2、按增量序列个数k,对序列进行k趟排序;
3、每趟排序,根据对应的增量ti,将待排序列分割成若干长度为m的子序列,分别对各子表惊醒直接插入排序。仅增 量因子为1时,整个序列作为一个表来处理,表长度即为整个序列的长度。
示例:
算法的实现:
首先简单处理增量序列:增量序列 d = {n/2,n/4,n/8.........1}n为要排序的个数
即:先将要排序的一组记录按某个增量d(n/2,n要为整个排序数的个数)分成若干个子序列,然后再用一个较小的增量(d/2)对她进行分组,在每组中在进行直接插入排序,继续不断的缩小增量直至为1,最后使用直接插入排序完成排序。
完整代码:
<span style="font-size:14px;">#include<stdio.h>
void print(int a[],int n,int i)
{
int j;
printf("第 %d 趟: ",i);
for(j = 0;j < n;j++)
{
printf("%d ",a[j]);
}
printf("\n");
}
/*
* 直接插入的一般形式
* dk为缩小增量,如果dk = 1,则为直接插入排序
*/
void shellInsertSort(int a[],int n,int dk)
{
int i;
printf("增量为%d:\n",dk);
for(i = dk; i < n; i++)
{
if(a[i] < a[i-dk]) //若第i个元素大于i-1元素,直接插入。小于的话,移动有序表后插入
{
int j = i - dk;
int x = a[i]; //复制为哨兵,即存储待排序元素
a[i] = a[i-dk]; //首先后移一个元素
while(x < a[j]) //查找在有序表的插入位置
{
a[j+dk] = a[j]; //元素后移
j -= dk;
}
a[j+dk] = x; //插入到正确位置
}
print(a,9,i);
}
}
//先按增量d(n/2)为待排序列进行希尔排序
void shellSort(int a[],int n)
{
int dk = n / 2; //增量
while(dk >= 1)
{
shellInsertSort(a,9,dk);
dk = dk / 2;
}
}
int main()
{
int a[] = {5,1,6,8,4,2,9,7,3};
//shellInsertSort(a,9,1); //直接插入排序
shellSort(a,9); //希尔排序
return 0;
}</span>
运行结果:
希尔排序是一个不稳定排序
注:希尔排序的时效分析很难,他的比较次数和元素的移动次数都与增量因子dk的选取有关。增量因子序列有各种取法,如:取奇数、取质数等,但是要注意的是:增量因子中除1外没有公因子,且最后一个增量因子必须为1;