希尔排序详解

希尔排序详解

1、希尔排序思想

  • 希尔排序是通过设置间隔,而对于每个间隔上的元素再进行插入排序,一趟排序后,间隔变小,再继续对此次间隔上的元素进行插入排序,直到间隔为1,此时就是一次完整的直接插入排序。(直接插入排序可以看我另一篇博客)

  • 这里的代码和图解都是降序

2、排序过程图解

  • 间隔为3时的部分图解每趟都是间隔为3的元素之间的一次直接插入排序。其中 i 控制end的走法,endgap控制每次排序的走法。

  • 间隔为1时的部分图解每趟都是间隔为1的元素之间的一次直接插入排序

3、排序代码

  • 方法一:这里 j 控制 ii 控制 end第一层for循环控制 i 走到 gap-1,即使得下面j能访问到所有元素。第二层for循环用来对endj开始到n-gap-1间隔为 gap 的所有排序。

    //希尔排序
    void ShellSort(int *arr, int n) {
        int gap = n;
        while (gap > 1) {
            gap = gap / 3 + 1; //这里控制每次gap递减
            for (int j = 0; j < gap; ++j) { //这里控制 i 走到 gap-1
                for (int i = j; i < n - gap; i += gap) {//一趟排序把所有这次gap的元素排序好
                    int end = i;
                    int tmp = arr[end + gap];
                    while (end >= 0) {
                        if (tmp < arr[end]) {
                            arr[end + gap] = arr[end];
                        } else {
                            break;
                        }
                        end -= gap;
                    }
                    arr[end + gap] = tmp;
                }
            }
        }
    }
    
  • 方法二:这里代码就和上面的图解思想一样,我们注意到这里 gap 每次减少是用这个 gap = gap / 3 + 1表达式,这个递减方法的效率相对于其他表达式要更高。如下图示。

    • 其中,希尔排序的时间复杂度是O(n^1.3),这是官方的解释。
    //希尔排序
    void ShellSort(int *arr, int n) {
        int gap = n;
        while (gap > 1) {
            gap = gap / 3 + 1;
            for (int i = 0; i < n - gap; i += gap) {
                int end = i;
                int tmp = arr[end + gap];
                while (end >= 0) {
                    if (tmp < arr[end]) {
                        arr[end + gap] = arr[end];
                    } else {
                        break;
                    }
                    end -= gap;
                }
                arr[end+gap] = tmp;
            }
        }
    }
    

    递减表达式gap = gap / 3 + 1处理1亿条数据的时间:

    递减表达式gap = gap / 2处理1亿条数据的时间:

  • 方法三:这个方法可以看到,只有一处与上处代码不一样,也就是for循环里面分别为 i + = gap i++。但是这个方法和上面方法的效率是一样的。排序图解下面浅浅的展示一下。

    //希尔排序
    void ShellSort(int *arr, int n) { 
    		int gap = n;
        while (gap > 1) {
            gap = gap / 3 + 1;
            //预排序
            for (int i = 0; i < n - gap; i++) {
                int end = i;
                int tmp = arr[end + gap];
                while (end >= 0) {
                    if (tmp < arr[end]) {
                        arr[end + gap] = arr[end];
                    } else {
                        break;
                    }
                    end -= gap;
                }
                arr[end + gap] = tmp;
            }
        }
    }
    

    此处仅演示 gap = 3 的部分情况排序,gap = 1 的排序情况自行思考。

    • 时间复杂度计算O(n^1.3) —>官方解释
    • 空间复杂度计算:由于没有开辟额外空间来辅助数组排序,故空间复杂度为O(1)
    • 算法稳定性不稳定,考虑序列(2,2,1),排序后序列为(1,2,2),我们发现2的相对位置发生了变化,所以是不稳定的排序算法。

ok,希尔排序算法就到这里。下面是我的github主页,里面记录了我的学习代码和leetcode的一些题的题解,有兴趣的可以看看。

Xpccccc的github主页

  • 24
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 23
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 23
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Xpccccc

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值