希尔排序
直接插入排序的时间复杂度在元素有序或者是元素数量少的时候是比较有效的,希尔排序为了提高算法的效率,所以将原始的元素进行分组使每个分组的元素个数较少,然后在这些分组中进行直接插入排序,当整个序列基本有序的时候再接着进行一次直接插入排序。
基本思想:假设有n个数据元素
先取一个小于n的整数d1作为第一个增量,把文件的全部记录分成d1个组。所有距离为dl的倍数的记录放在同一个组中。先在各组内进行直接插人排序;然后,取第二个增量d2<d1重复上述的分组和排序,直至所取的增量dt=1(dt<dt-l<…<d2<d1),即所有记录放在同一组中进行直接插入排序为止。最后一次的增量一定是1,也就是对所有的元素进行一次直接插入排序。
实例:
假设待排序文件有10个记录,其关键字分别是:
49,38,65,97,76,13,27,49,55,04
增量序列的取值依次为:
5,3,1
第一趟排序:
49,38,65,97,76,13,27,49,55,04//增量为5,所以49与38比较,互换,其余同样
第二趟排序:
13,27,49, 55,04,49,38,65,97,76//增量为3.所以对13,04,97进行直接插入排序
04,27,38 ,55 ,13 ,49 ,49 ,65 , 97,76
最后一趟排序直接进行一次直接插入排序,参照之前的算法。由于现在的元素已经基本有序,所以时间复杂度降低。
希尔排序是第一种时间复杂度突破O(n^2)的排序算法,平均时间复杂度为(O(nlgn)~O(n^2))
代码
void ShellSort(SeqList R)
{
int increment=n; //增量初值,不妨设n>0
do {
increment=increment/3+1; //求下一增量
ShellPass(R,increment); //一趟增量为increment的Shell插入排序
}while(increment>1)
} //ShellSort
void ShellPass(SeqList R,int d)
{//希尔排序中的一趟排序,d为当前增量
for(i=d+1;i<=n;i++) //将R[d+1..n]分别插入各组当前的有序区
if(R[i].key<R[i-d].key){
R[0]=R[i];j=i-d; //R[0]是暂存单元
do {//查找R[i]的插入位置
R[j+d];=R[j]; //后移记录
j=j-d; //查找前一记录
}while(j>0&&R[0].key<R[j].key);
R[j+d]=R[0]; //插入R[i]到正确的位置上
} //endif
} //ShellPass