天天看点

C++算法之希尔排序--(6)

1.希尔排序:

         希尔排序(Shell's Sort)是插入排序的一种又称“缩小增量排序”(Diminishing Increment Sort),是直接插入排序算法的一种更高效的改进版本。希尔排序是非稳定排序算法。时间复杂度O(n^2)。

2.原理及基本思想:

        希尔排序是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含的关键词越来越多,当增量减至1时,整个文件恰被分成一组,算法便终止。

        先取一个小于n的整数d1作为第一个增量,把文件的全部记录分组。所有距离为d1的倍数的记录放在同一个组中。先在各组内进行直接插入排序;然后,取第二个增量d2<d1重复上述的分组和排序,直至所取的增量  =1(  <  …<d2<d1),即所有记录放在同一组中进行直接插入排序为止。其实质上就是一种分组插入方法。

3.代码示例:          

void swapInt(int * a,int*b)
{
 int c=*a;
 *a=*b;
 *b=c;
}
void shell(int*data,unsigned int len)
{
 if(len<=1||data==NULL)
  return;
 for(int div=len/2;div>=1;div=div/2)//定增量div,并不断减小
 {
  for(int i=0;i<=div;++i)//分组成div组
  {
   for(int j=i;j<len-div;j+=div)//对每组进行插入排序
    for(int k=j;k<len;k+=div)
     if(data[j]>data[k])
      swapInt(data+j,data+k);//交换两个数的值
  }
 }
}
           

4.算法实现分析

    不设监视哨的算法描述:

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的插入位置

R[j+d]=R[j]; //后移记录

j=j-d; //查找前一记录

}while(j>0&&R[0].key<R[j].key);

R[j+d]=R[0]; //插入R到正确的位置上

} //endif

5.优缺点分析

      希尔排序不需要大量的辅助空间,和归并排序一样容易实现。希尔排序是基于插入排序的一种算法, 在此算法基础之上增加了一个新的特性,提高了效率。希尔排序的时间复杂度与增量序列的选取有关,例如希尔增量时间复杂度为O(n²),而Hibbard增量的希尔排序的时间复杂度为O(  ),希尔排序时间复杂度的下界是n*log2n。希尔排序没有快速排序算法快 O(n(logn)),因此中等大小规模表现良好,对规模非常大的数据排序不是最优选择。但是比O(  )复杂度的算法快得多。并且希尔排序非常容易实现,算法代码短而简单。 此外,希尔算法在最坏的情况下和平均情况下执行效率相差不是很多,与此同时快速排序在最坏的情况下执行的效率会非常差。专家们提倡,几乎任何排序工作在开始时都可以用希尔排序,若在实际使用中证明它不够快,再改成快速排序这样更高级的排序算法. 本质上讲,希尔排序算法是直接插入排序算法的一种改进,减少了其复制的次数,速度要快很多。 原因是,当n值很大时数据项每一趟排序需要移动的个数很少,但数据项的距离很长。当n值减小时每一趟需要移动的数据增多,此时已经接近于它们排序后的最终位置。 正是这两种情况的结合才使希尔排序效率比插入排序高很多。

继续阅读