手把手教你学会希尔排序,很简单!

举报
Tom forever 发表于 2019/10/26 10:46:28 2019/10/26
【摘要】 前面我写过一篇文章:这几个经典的基础排序算法,你还记得吗?这篇文章中我带大家回忆了一下冒泡排序、选择排序和插入排序三种经典的排序算法,他们的时间复杂度均为 O(N^2),效率不高。这篇文章我们讨论一个高级一点排序算法:希尔排序。很多朋友看到一些算法的名字就望而却步,其实没有必要,我们每个人只要愿意迈出那一步,后面将会迎来更多更好的东西。这篇文章手把手带你学会希尔排序的原理,最后给出代码实现。...

前面我写过一篇文章:这几个经典的基础排序算法,你还记得吗?这篇文章中我带大家回忆了一下冒泡排序、选择排序和插入排序三种经典的排序算法,他们的时间复杂度均为 O(N^2),效率不高。

这篇文章我们讨论一个高级一点排序算法:希尔排序。很多朋友看到一些算法的名字就望而却步,其实没有必要,我们每个人只要愿意迈出那一步,后面将会迎来更多更好的东西。这篇文章手把手带你学会希尔排序的原理,最后给出代码实现。

希尔排序是基于插入排序的,我们知道,插入排序有个弊端,假设一个很小的数据项在很靠近右端的位置上,那么所有的中间数据项都必须向右移动一位,这个步骤对每一个数据项都执行了将近N次的复制,这也是插入排序效率为 O(N^2) 的原因。

希尔排序的中心思想是将数据进行分组,然后对每一组数据进行插入排序,在每一组数据都有序后,再对所有的分组利用插入排序进行最后一次排序。这样可以显著减少数据交换的次数,以达到加快排序速度的目的。

这种思想需要依赖一个增量序列,我们称为 n-增量,n 表示进行排序时数据项之间的间隔,习惯上用 h 表示。为了很好的理解增量排序,我们看下面的示意图:

640?tp=webp&wxfrom=5&wx_lazy=1&wx_co=1



上图显示了增量为 4 时对 10 个数据项进行排序的示意图,一趟后 0、4、8 三个位置上的数据项已经排好序,接下来,算法向右移动一步,对 1、5、9 三个位置的数据项进行排序,这个过程一直持续进行,直到所有数据项都完成了一次 4-增量排序,然后缩小增量,再重复上面的过程,最后一次增量为 1,对所有的数据项进行一次插入排序,从而完成了希尔排序的全部步骤。因为最后一趟都已经基本有序了,所以复杂度没有向普通插入排序那么大了。

说到这里,大家应该可以明白,增量序列在希尔排序中是很重要的。一般好的增量序列都有 2 个共同的特征:


  • 1. 最后一个增量必须为1,保证最后一趟是一次普通的插入排序;

  • 2. 应该尽量避免序列中的值(尤其是相邻的值)互为倍数的情况



这篇文章中我们使用增量序列用 h = 3 * h + 1 来生成。h 初值被赋予 1,然后使用该公式生成序列 1、4、13、40、121、364 等等,当间隔大于数组大小的时候停止,使用序列的最大数组作为间隔开始希尔排序过程,然后没完成一次排序,用倒推公式 h = (h - 1) / 3来减小间隔,保证最后一次 h=1,完成最后一次插入排序。

说完了原理,下面看看具体实现代码:


public void shellSort2() {    int h = 1;    while(h <= nElem / 3) {        h = h * 3 + 1; //增量间隔    }        while(h > 0) {        for(int i = h; i < nElem; i++) {            //每个增量间隔内,实现插入排序,两个for循环和插入排序一样,只不过第二个for循环里参数略有调整而已,和h有关            for(int j = i; j < nElem; j += h) {                for(int k = j; (k - h >= 0) && a[k] < a[k - h]; k -= h) {                    swap(k, k-h);                }            }        }        h = (h-1) / 3;    }}



算法分析:希尔排序时间复杂度平均为 O(NlogN),最好与最坏情况要根据具体的增量序列来判断,对于不同的增量序列有不同的复杂度。希尔排序的性能优于直接插入排序,因为在希尔排序开始时增量较大,分组较多,每组的记录数目少,故各组内直接插入较快,后来随着增量逐渐缩小,分组数逐渐减少,而各组的记录数目逐渐增多,但是由于已经局部排过序了,所以已经接近有序状态,新的一趟排序过程也较快。因此,希尔排序在效率上较直接插入排序有较大的改进。

希尔排序是不稳定的,因为不同的间隔对应的数据是独自比较的,如果 a=b,但是不在同一个间隔上,显然会出现前后颠倒的情况,所以希尔排序是不稳定的。

空间复杂度为 O(1),不需要额外的存储空间。





转载声明:本文转载自公众号【程序员私房菜】。    

原文链接:https://mp.weixin.qq.com/s/MOf90xTn0K-8iGq0i5i-5g





【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。