数据结构和算法学习之路——希尔排序详解(C++版)

数据结构和算法学习之路——希尔排序详解(C++)

Many things in life are not what we can not do, but we do not believe that we can achieve them.
——生活中的许多事,并不是我们不能做到,而是我们不相信能够做到。

在上一篇博文里面我们学习了直接插入排序,其实呢,插入排序的大家庭里面可不仅仅只有直接插入排序哦,还有比如说折半插入排序,2-路插入排序等等,但是大家还记得么,这些算法的时间复杂度都没能突破O(n²),然而今天我们要讨论的这一个算法,同时该算法是冲破O(n²)的第一批算法之一:
它就是——希尔排序(也称缩小增量排序),是插入排序的升级版本

在本文中,我将和大家一起探讨该算法的过程,代码实现,而关于希尔排序的时间复杂度的研究一直是一个难题

1.希尔排序的具体过程

希尔排序在数组中采用跳跃式分组的策略,通过某个增量将数组元素划分为若干组,然后分组进行插入排序,随后逐步缩小增量,继续按组进行插入排序操作,直至增量为1,最后一步也就是回到了直接插入排序,但是此时整个数组已经基本宏观有序,只需要调整个别元素的位置,所以时间上的开销是比较小的
我们以下面的数组为例

int a[10] = {9, 1, 2, 5, 7, 4, 8, 6, 3, 5};

这个图是百度上的,我觉得画的挺不错的,但是其实我感觉gap用increment(增量)代替会比较容易理解,下面我们来分析分析这个过程:

数据结构和算法学习之路——希尔排序详解(C++版)_第1张图片
首先,整个数组的长度位10,因此我们的增量increment取数组的长度(length)/2
说明:这里的increment的取值不是唯一的,有学者提出用increment = increment / 3 + 1 效率更高,而且关于增量如何选择也是一个数学难题,这里我们暂且用希尔本人提出的
increment = imcrement / 2 来计算增量

  1. 第一次分组,increment = 5,因此我们把数组中增量为5的数分为一组,像上图那样分,同样颜色的数字代表一组,因此整个数组就被分成了5组,每组只有两个数字
  2. 下面我们对每组的数字进行直接插入排序,注意我们的比较不再像直接插入排序那样一位一位的比,而是以increment为准,跳跃式的比较并且交换
  3. 那么第一趟排序的结果就是
    4 1 2 3 5* 9 8 6 5 7 (5*是为了区别后面那个5)
  4. 当进行完第一次排序之后,我们让increment / 2 以这个新的增量再次对该数组进行划分,第二次的increment为5/2 = 2,所以数组中增量为2的数字就被划为了新的组
  5. 继续进行上述操作,直到排序完成

2.希尔排序的C++实现

void shellsort(int a[], int length)
{
    int i, j, k, temp, increment;
    for(increment = length / 2; increment > 0; increment /= 2)  //这个是增量每次变化的循环,下面所有的操作都要在这个大循环下进行
    {
        for(i = 0; i < increment; i++)    
        {
            for(j = i + increment; j < length; j += increment)    //分组操作
            {
                if(a[j] < a[j - increment])
                {
                    temp = a[j];
                    for(k = j - increment; k >= 0 && a[k] > temp; k -= increment)
                    {
                        a[k + increment] = a[k];    //元素的移动操作
                    }
                    a[k + increment] = temp;
                }
            }
        }
    }
}

3. 希尔排序的时间复杂度分析

希尔排序的时间复杂度与增量序列的选取有关,例如希尔增量时间复杂度为O(n²),而Hibbard增量的希尔排序的时间复杂度为O(n的二分之三次方),希尔排序时间复杂度的下界是O(n*log2n)。希尔排序没有快速排序算法快 O(n(logn)),因此中等大小规模表现良好,对规模非常大的数据排序不是最优选择。但是比O(n²)复杂度的算法快得多。并且希尔排序非常容易实现,算法代码短而简单。 此外,希尔算法在最坏的情况下和平均情况下执行效率相差不是很多,与此同时快速排序在最坏的情况下执行的效率会非常差。
本文中使用的是希尔增量

你可能感兴趣的:(数据结构和算法)