排序之希尔排序

来源:互联网 发布:倩女手游 mac 编辑:程序博客网 时间:2024/05/02 00:17

                               排序之希尔排序

    希尔排序属于插入排序的一种方式,不同于直接插入排序,希尔排序实际上是一种分组插入排序。先来说一下它的基本思想:先取定一个小于n的整数d1作为第一个增量,把表的全部元素分成d1个组,所有相互之间距离为d1的倍数的元素放在同一个组中,在各组内进行直接插入排序;然后,取第二个增量d2(d2<d1),重复上述的分组和排序过程,直至所取的增量d(t)=1(d(t)<d(t-1)<……d2<d1),即所有元素放在同一组中进行直接插入排序。

    希尔排序在每趟并不产生有序区,在最后一趟排序结束前,所有元素并不一定归位。但是在每趟排序完成后,数据越来越接近有序。因为具体实现与前面总结的直接插入排序有相似之处,这里先多说一下关于希尔排序时间复杂度的问题再最后给出代码。

    希尔排序的性能分析是一个复杂的问题,因为它的时间复杂度是所取“增量”的函数,而到目前为止增量的选取无一定论,因而它的时间复杂度难以分析,一般认为其平均时间复杂度为O(n^1.3)。希尔排序的速度通常要比直接插入排序快,可以这样理解:在希尔排序开始时增量d1较大,分组较多,每组的元素数目少,故各组内直接插入排序较快,后来增量d(i)逐渐缩小,分组数逐渐减少。而各组内的元素数目逐渐增多,但由于已经按d(i-1)作为增量排过序,使表较接近有序状态,所以新的一趟排序过程也较快。因此,希尔排序在效率上较直接插入排序有较大的改进。

   希尔排序算法中使用了多重循环,因而我们要对每一层循环的目的有清晰的认识,在算法中使用了较多的辅助变量,但与问题规模无关,属于就地排序。下面给出一种可行的实现方式,增量初始设置为n/2,每进行完一次对所有组的组内直接插入排序,增量变为n/2,直到增量为1(即对所有的数字进行一次直接插入排序)为止,此时排序完成。代码如下,关键代码的解释写在注释里,便于查看:

//包含了直接插入排序void Sort_shell(int *a, int n){       inti,j,gap;       for(gap=n/2;gap>0; gap/=2)//gap代表了选取的增量,即每次分几组,也即组内元素的距离最小值//在每组的组内再进行直接插入排序       {              for(i=0;i<gap; i++)//gap组数字全部进行下面的直接插入排序              {                     //每组的组内数字进行直接插入排序                     for(j=i+gap;j<n; j+=gap)                            if(a[j]<a[j-gap])                            {                                   inttemp = a[j];                                   intk = j-gap;                    //边比较边进行移动覆盖,直到把该元素插入到合适的位置//然后再进行同一组内的下一个元素的直接插入排序,直到该组排序结束                                   while(k>=0&& a[k]>temp)                                   {                                          a[k+gap]= a[k];                                          k-=gap;                    }                                   a[k+gap]=temp;                            }              }       }}


还是举例说明一下:

 

初始数组:      元素下标 0  1  2 3  4   5  6  7

                          元素值 12  8  4 7  3  16 2  5

 

第一次分组插入排序:

gap=4 共四组(12,3) (8,16)  (4,2) (7,5)

排序结束元素顺序为:3  8 2  5  12 16  4  7

第二次分组插入排序:

gap=2 共两组 (3  2  12 4)  (8  5  16  7)

排序结束元素顺序为:2  5 3  7  4 8  12  16

第三次分组插入排序:

gap=1 共一组(2 5  3  7 4  8  12  16)

排序结束元素顺序为:2  3 4  5  7 8  12  16

至此,整个排序过程结束

类似于直接插入排序,再给出一种简化的代码实现方式:

 

void Sort_Shell(int *a ,int n){ int i,j,gap;for(gap=n/2; gap>0; gap/=2)  for(i=gap; i<n; i++)//不同组的数字交替的进行插入排序,比较难想,建议在纸上把程序走一遍    for(j=i-gap; j>=0&& a[j]>a[j+gap]; j-=gap)       swap(a[j],a[j+gap];)}

0 0
原创粉丝点击