希尔排序算法

    希尔排序Shell Sort)是 D.L.Shell 于1959 年提出来的一种排序算法,在这之前排序算法的时间复杂度基本都是O(n2)的,希尔排序算法是突破这个时间复杂度的第一批算法之一。
    直接插入排序,应该说,它的效率在某些时候是很高的,比如,我们的记录本身就是基本有序的,我们只需要少量的插入操作,就可以完成整个记录集的排序工作,此时直接插入很高效。还有就是记录数比较少时,直接插入的优势也比较明显。可问题在于,两个条件本身就过于苛刻,现实中记录少或者基本有序都属于特殊情况。
    不过别急,有条件当然是好,条件不存在,我们创造条件,也是可以去做的。于是科学家希尔研究出了一种排序,对直接插入排序改进后可以增加效率的方法。
    如何让待排序的记录个数较少呢?很容易想到的就是将原本有大量记录数的记录进行分组。分割成若干个子序列,此时每个子序列待排序的记录个数就比较少了。然后在这些子序列内分别进行直接插入排序,当整个序列都基本有序时,注意只是基本有序时,再对全体记录进行一次直接插入排序。


    在介绍算法之前,先定义一个数组。

   #define LEN 11

   int number[LEN] = {0, 25, 19, 6, 58, 34, 10, 7, 98, 160, 0};  

   // number[0]是作为哨兵用的,并不属于待排序数列,待排序数列为number[1]...number[LEN]。

   具体算法如下:

void ShellSort(int *s, int n)
{
    int i, j;
    int d = n - 1;        // d为增量, 初始值为待排列数据个数              
    while(d > 1) {
        d = d / 2;        // 增量变化
        for(i = d + 1; i != n; i++)
        {  
            // 直接插入排序
            if(s[i] < s[i-d])  // 将一组中相邻的的两个数比较  
            {
                s[0] = s[i];
                for(j = i - d; j > 0 && s[0] < s[j]; j -= d)
                    s[j+d] = s[j];
                s[j+d] = s[0];
            }
        }
    }
}

     

      1)第一次的增量d = 5, 需要比较的数据和排序的数据是s[1]和s[6]、s[2]和s[7].....s[5]和s[10]。       整个希尔排序的算法过程如下如所示:

79ab1624f331df484d088dea.jpg
      2)本次排序的结果如下图:

           第二次的增量为2,需要排序的是s[1] s[3] s[5] s[7] s[9]、s[2] s[4] s[6] s[8] s[10]。

           对每一组需要排序的数列,使用的是直接插入法。

   eb2a341386ff7f6adc5401f5.jpg

     3) 本次排序的结果如下图:

           第三次的增量为1,需要排序的是s[1] s[2] s[3] s[4] s[5] s[6] s[7] s[8] s[9] s[10]。

           对这一组需要排序的数列,使用直接插入法。

f3512ec84e2bbf5e7e3e6ff7.jpg

      4) 当d=1 是进行最后一次排序。最终结果如下:

cdfffc4f5d40817faec3abf2.jpg

  希尔排序的具体思路就是这样。


   通过这段代码的剖析,相信大家有些明白,希尔排序的关键并不是随便的分组后各自排序,而是将相隔某个“增量”的记录组成一个子序列,实现跳跃式的移动,使得排序的效率提高。
     这里“增量”的选取就非常关键了。我们在代码中第7行,是用d = d / 2; 的方式选取增量的,可究竟应该选取什么样的增量才是最好,目前还是一个数学难题,迄今为止还没有人找到一种最好的增量序列。不过大量的研究表明,当增量序列为dlta[k]=2t-k+1-1(0≤k≤t≤log2(n+1))时,可以获得不错的效率,其时间复杂度为O(n3/2),要好于直接排序的O(n2)。需要注意的是,增量序列的最后一个增量值必须等于1才行。另外由于记录是跳跃式的移动,希尔排序并不是一种稳定的排序算法。
     不管怎么说,希尔排序算法的发明,使得我们终于突破了慢速排序的时代(超越了时间复杂度为O(n2)),之后,相应的更为高效的排序算法也就相继出现了。


你可能感兴趣的:(希尔排序)