10.2 插入排序(2)

希尔排序是由Donald Shell提出的,能够突破O(n²)时间复杂度限制的排序算法。通过逐步减少增量并进行插入排序,使整个序列最终有序。本文详细介绍了希尔排序的核心思想、实现方法及其时间与空间复杂度。

核心思想

希尔排序(Shell Sort)是Donald Shell命名的,是第一个突破O(n2)时间的排序算法之一。希尔排序的核心在于选取恰当的增量d,对于线性表A[1..n],对任意的t[1,n]A[t],A[t+d],A[t+2d],...看作是新的表,将其进行一次插入排序,然后缩小增量d,再如法炮制,直到增量d=1进行最后一次整体的插入排序。因此,希尔排序又被称为增量递减排序(diminishing increment sort)。希尔排序的核心在于如何选取这个增量序列d。Donald Shell本身提出使用递推函数dk+1=dk2,这也是教材上给出的增量,但是实际上该序列的性能并不是很好。

实现

希尔排序相较于普通插入排序,多的就在于增量上。因此实现时,增加了一个函数指针参数,用来设置增量。最外层的while循环终止条件是增量d == 0,在此之前必然经历了增量为1的插入排序,因此序列就有序了。在外层while循环内,可以看到和普通插入排序极为相似的地方,区别就在于并不是保证整体有序,而是保证以增量为d的子序列有序。在实现过程中,和之前一样,也要注意插入排序内层循环两个终止条件要保持一致;以及j = i - d的含义。
下面就给出一个C++实现供参考。

/**
* 希尔增量函数
* @param int x 原增量
* @return int 经过一次迭代后新的增量
*/
int shell_increment(int x){
    return x / 2;
}
/**
* 希尔排序
* @param std::vector<_Ty> & a 需要排序的表
* @param int(*increment_func)(int x) 增量序列函数的指针
*/
template<typename _Ty>
void shell_sort(std::vector<_Ty> & a, int(*increment_func)(int x)){
    int i, j, d;
    int round = 0;    //指示进行了第几次迭代,观察输出用
    d = (*increment_func)(a.size());    //求出初始增量值
    while (d > 0){    //保证增量d > 0。最后一次迭代增量必然为1。
        for (i = d; i < a.size(); i++){
            _Ty tmp = a[i];
            //同10.2(1)中有讲,要保证两个循环终止条件的一致性
            //都要将终止时的指针(下标)指向应该放入的位置的前一个元素
            for (j = i - d; j >= 0 && a[j] > tmp; j -= d)
                a[j + d] = a[j];
            a[j + d] = tmp;
        }
        //输出每一次迭代后的表
        std::cout << "Round " << ++round << " : " << " d = " << d << std::endl;
        output_list(a);
        //减小增量
        d = (*increment_func)(d);
    }
}

对于上例的输入数据5 4 11 18 1 70 35 90 100 2,可以看出最外层每一次迭代的结果。
第一次迭代保证了5-704-35…这样增量为5的有序,第二次保证了1-5-11-35-1002-4-18-70-90增量为2的有序。但是在最后一次迭代之前,始终不能保证整体有序。

Round 1 :  d = 5
5       4       11      18      1       70      35      90      100     2
Round 2 :  d = 2
1       2       5       4       11      18      35      70      100     90
Round 3 :  d = 1
1       2       4       5       11      18      35      70      90      100

时间空间复杂度以及稳定性

希尔排序的空间复杂度和普通插入排序类似,都是O(1)。对于空间复杂度来说,由于增量序列选取的不同,时间复杂度也是不同的,而且也较难分析。一般情况下认为是一种次二次nt,1<t<2)的时间复杂度,对于例子中的Shell Increment,有着最坏的O(n2)运行时间。希尔排序的效率通常情况下好于普通插入排序,因为普通插入排序对于数据近乎有序的时候效率很高,而希尔排序将后面元素较多时的插入排序的输入变得尽量有序。
稳定性方面,希尔排序是不稳定的。可以举出反例说明,这里就略去了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值