草庐IT

【排序算法】希尔排序(C语言)

手眼通天王水水 2023-04-28 原文

【排序算法】—— 希尔排序

目录

希尔排序是对直接插入排序的优化,在学习之前,没有学过插入排序的童鞋们建议先学习插入排序:点击跳转到插入排序😜

一、希尔排序原理

1. 插入排序的问题

​ 逆序有序的数组排序时,时间复杂度为 O ( n 2 ) O(n^2) O(n2),此时效率最低

​ 顺序有序的数组排序时,时间复杂度为 O ( n ) O(n) O(n),此时效率最高

​ 我们发现,当被排序的对象越接近有序时,插入排序的效率越高,那我们是否有办法将数组变成接近有序后再用插入排序,此时希尔大佬就发现了这个排序算法,并命名为希尔排序

2. 希尔排序的思路

​ 希尔排序是对插入排序的优化,基本思路是先选定一个整数作为增量,把待排序文件中的所有数据分组,以每个距离的等差数列为一组,对每一组进行排序,然后将增量缩小,继续分组排序,重复上述动作,直到增量缩小为1时,排序完正好有序。

​ 希尔排序原理是每一对分组进行排序后,整个数据就会更接近有序,当增量缩小为1时,就是插入排序,但是现在的数组非常接近有序,移动的数据很少,所以效率非常高,所以希尔排序又叫缩小增量排序

​ 每次排序让数组接近有序的过程叫做预排序,最后一次插入是直接插入排序

  1. 以3作为增量对数组进行分组,以下数组被分成3组,每组之间都是以3的等差数列

  1. 对每一组进行插入排序,得到如下数组

  1. 此时增量缩小,以2为增量对数组进行分组,数组被分成2份,每组之间都是2的等差数列

  1. 对每一组进行插入排序,得到如下数组

  1. 最后增量为1,分为1组(其实就等于没分),对其进行插入排序,数组变得有序

二、希尔排序的相关问题

1. 为什么插入排序那么多但效率却很高

  1. 希尔排序中待排数据每次是以增量的移动步数空出插入位置,所以效率比普通插入一次一步的移动方式要快

  1. 每一次排序之后数组就会变得接近有序,插入排序的移动次数就会越来越少,效率也不是普通的插入排序能比的了

  2. 希尔排序移动次数:共移动8步

  1. 直接插入排序移动次数:共移动15步

综上所述:希尔排序在越大的数组上更能发挥优势,因为步子迈的更大,减少插入排序的移动次数更多

2. 如何选择希尔增量

​ 希尔排序的分析是一个复杂的问题,它的时间是一个关于增量序列的函数,这涉及到一些数学上未能攻克的难题,所以目前为止对于希尔增量到底怎么取也没有一个最优的值,但是经过大量研究已经有一些局部的结论,在这里并不展开叙述。

​ 最初希尔提出的增量是 gap = n / 2,每一次排序完让增量减少一半gap = gap / 2,直到gap = 1时排序变成了直接插入排序。直到后来Knuth提出的gap = [gap / 3] + 1,每次排序让增量成为原来的三分之一,加一是防止gap <= 3gap = gap / 3 = 0的发生,导致希尔增量最后不为1,无法完成插入排序。到目前为止业内对于两个大佬的方法依然是看法不一,都没有比出个上下来

​ 我们目前使用的则是Knuth提出的除三法获得希尔增量来演示

三、代码实现

1. 代码实现思路

​ 希尔排序的代码实现比较魔幻,由于我们讲解的希尔排序的思路是将分组进行直接插入排序,就导致我们容易产生疑惑,是不是分多少组就调用多少次插入排序的代码呢,那这代码量不就随着增量的变化而变化了,但是动态代码这个概念听着就让人倍感稀奇。所以我们仅用一次遍历数组的方式就巧妙对每个分组完成单趟排序,不需要对代码做那样鬼畜的操作

  1. 当我们以希尔增量开始遍历时,由于一次跨gap访问下一个数据,所以我们用i变量从0遍历到size-gap-1处,即红色箭头处

  1. i=0时,我们用end变量从后往前遍历插入,将end+gap作为下一个数据的位置,此时end+gap数据大于end处数据,原地插入(不做插入)即可。(g箭头指向end+gap处的数据)

  1. 此时i++end再次往前遍历,找end+gap处数据该插入的位置,6依然大于3,不做插入

  1. i接着向后遍历,end变量找end+gap处数据该插入的位置,2依然大于4,不做插入

  1. i还是遍历,end变量向前找到end+gap处数据的插入位置,7比8小,end向前移动gap位,将该数据插入到此时的end+gap位置

  1. i遍历到下一个,此时end+gap为1,比6小,end向前移动gap位,将该数据插入到此时的end+gap位置
  2. 此时end+gap为1,依然比end处的3小,end继续减gap,在end+gap处继续插入(此时end < 0,但是我们以end+gap作为插入位置,所以不会造成数组越界)

  1. 此时i不用动了,刚好到size-gap-1处,循环结束,第一趟遍历就结束了

  1. 然后缩小增量gap = gap / 3 + 1gap = 1,接着插入排序,直到排序完成

​ 这个过程相当于对每个分组按照一个固定顺序轮流插入排序,并且它们是以一个元素为单位同时进行的,而不是先将某个分组插入排序完再下一个分组。

2. 实现代码

void ShellSort(int* arr, int size)
{
    int gap = size;
    while (gap > 1)
    {
        gap = gap / 3 + 1;	//调整希尔增量
        int i = 0;
        for (i = 0; i < size - gap; i++)	//从0遍历到size-gap-1
        {
            int end = i;
            int temp = arr[end + gap];
            while (end >= 0)
            {
                if (arr[end] > temp)
                {
                    arr[end + gap] = arr[end];
                    end -= gap;
                }
                else
                {
                    break;
                }
            }
            arr[end + gap] = temp;	//以 end+gap 作为插入位置
        }
    }
}

有关【排序算法】希尔排序(C语言)的更多相关文章

  1. ruby - 如何将脚本文件的末尾读取为数据文件(Perl 或任何其他语言) - 2

    我正在寻找执行以下操作的正确语法(在Perl、Shell或Ruby中):#variabletoaccessthedatalinesappendedasafileEND_OF_SCRIPT_MARKERrawdatastartshereanditcontinues. 最佳答案 Perl用__DATA__做这个:#!/usr/bin/perlusestrict;usewarnings;while(){print;}__DATA__Texttoprintgoeshere 关于ruby-如何将脚

  2. ruby - 寻找通过阅读代码确定编程语言的ruby gem? - 2

    几个月前,我读了一篇关于ruby​​gem的博客文章,它可以通过阅读代码本身来确定编程语言。对于我的生活,我不记得博客或gem的名称。谷歌搜索“ruby编程语言猜测”及其变体也无济于事。有人碰巧知道相关gem的名称吗? 最佳答案 是这个吗:http://github.com/chrislo/sourceclassifier/tree/master 关于ruby-寻找通过阅读代码确定编程语言的rubygem?,我们在StackOverflow上找到一个类似的问题:

  3. 区块链之加解密算法&数字证书 - 2

    目录一.加解密算法数字签名对称加密DES(DataEncryptionStandard)3DES(TripleDES)AES(AdvancedEncryptionStandard)RSA加密法DSA(DigitalSignatureAlgorithm)ECC(EllipticCurvesCryptography)非对称加密签名与加密过程非对称加密的应用对称加密与非对称加密的结合二.数字证书图解一.加解密算法加密简单而言就是通过一种算法将明文信息转换成密文信息,信息的的接收方能够通过密钥对密文信息进行解密获得明文信息的过程。根据加解密的密钥是否相同,算法可以分为对称加密、非对称加密、对称加密和非

  4. Unity 热更新技术 | (三) Lua语言基本介绍及下载安装 - 2

    ?博客主页:https://xiaoy.blog.csdn.net?本文由呆呆敲代码的小Y原创,首发于CSDN??学习专栏推荐:Unity系统学习专栏?游戏制作专栏推荐:游戏制作?Unity实战100例专栏推荐:Unity实战100例教程?欢迎点赞?收藏⭐留言?如有错误敬请指正!?未来很长,值得我们全力奔赴更美好的生活✨------------------❤️分割线❤️-------------------------

  5. 7个大一C语言必学的程序 / C语言经典代码大全 - 2

    嗨~大家好,这里是可莉!今天给大家带来的是7个C语言的经典基础代码~那一起往下看下去把【程序一】打印100到200之间的素数#includeintmain(){ inti; for(i=100;i 【程序二】输出乘法口诀表#includeintmain(){inti;for(i=1;i 【程序三】判断1000年---2000年之间的闰年#includeintmain(){intyear;for(year=1000;year 【程序四】给定两个整形变量的值,将两个值的内容进行交换。这里提供两种方法来进行交换,第一种为创建临时变量来进行交换,第二种是不创建临时变量而直接进行交换。1.创建临时变量来

  6. ruby-on-rails - 需要帮助最大化多个相似对象中的 3 个因素并适当排序 - 2

    我需要用任何语言编写一个算法,根据3个因素对数组进行排序。我以度假村为例(如Hipmunk)。假设我想去度假。我想要最便宜的地方、最好的评论和最多的景点。但是,显然我找不到在所有3个中都排名第一的方法。Example(assumingthereare20importantattractions):ResortA:$150/night...98/100infavorablereviews...18of20attractionsResortB:$99/night...85/100infavorablereviews...12of20attractionsResortC:$120/night

  7. ruby-on-rails - 在具有 ActiveRecord 条件的相关模型中按字段排序 - 2

    我正在尝试按Rails相关模型中的字段进行排序。我研究的所有解决方案都没有解决如果相关模型被另一个参数过滤?元素模型classItem相关模型:classPriority我正在使用where子句检索项目:@items=Item.where('company_id=?andapproved=?',@company.id,true).all我需要按相关表格中的“位置”列进行排序。问题在于,在优先级模型中,一个项目可能会被多家公司列出。因此,这些职位取决于他们拥有的company_id。当我显示项目时,它是针对一个公司的,按公司内的职位排序。完成此任务的正确方法是什么?感谢您的帮助。PS-我

  8. ruby - 按数字(从大到大)然后按字母(字母顺序)对对象集合进行排序 - 2

    我正在构建一个小部件来显示奥运会的奖牌数。我有一个“国家”对象的集合,其中每个对象都有一个“名称”属性,以及奖牌计数的“金”、“银”、“铜”。列表应该排序:1.首先是奖牌总数2.如果奖牌相同,按类型分割(金>银>铜,即2金>1金+1银)3.如果奖牌和类型相同,则按字母顺序子排序我正在用ruby​​做这件事,但我想语言并不重要。我确实找到了一个解决方案,但如果感觉必须有更优雅的方法来实现它。这是我做的:使用加权奖牌总数创建一个虚拟属性。因此,如果他们有2个金牌和1个银牌,加权总数将为“3.020100”。1金1银1铜为“3.010101”由于我们希望将奖牌数排序为最高的,因此列表按降序排

  9. ruby-on-rails - 在不重新查询数据库的情况下重新排序 Rails 中的事件记录? - 2

    例如,假设我有一个名为Products的模型,并且在ProductsController中,我有以下代码用于product_listView以显示已排序的产品。@products=Product.order(params[:order_by])让我们想象一下,在product_listView中,用户可以使用下拉菜单按价格、评级、重量等进行排序。数据库中的产品不会经常更改。我很难理解的是,每次用户选择新的order_by过滤器时,rails是否必须查询,或者rails是否能够以某种方式缓存事件记录以在服务器端重新排序?有没有一种方法可以编写它,以便在用户排序时rails不会重新查询结果

  10. ruby - 如何保持我不常用的编程语言技能 - 2

    关闭。这个问题是off-topic.它目前不接受答案。想改进这个问题吗?Updatethequestion所以它是on-topic用于堆栈溢出。关闭11年前。Improvethisquestion我不经常使用ruby​​-通常它加起来相当于每两个月或更长时间编写一次脚本。我的大部分编程都是使用C++进行的,这与ruby​​有很大不同。由于我与ruby​​之间的差距如此之大,我总是忘记语言的基本方面(比如解析文本文件和其他简单的东西)。我想每天练习一些基本的东西,我想知道是否有一些我可以订阅的网站,并且会向我发送当天的Ruby问题或类似的东西。有人知道这样的站点/Internet服务吗?

随机推荐