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

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

目录

  • 一、希尔排序原理
    • 1. 插入排序的问题
    • 2. 希尔排序的思路
  • 二、希尔排序的相关问题
    • 1. 为什么插入排序那么多但效率却很高
    • 2. 如何选择希尔增量
  • 三、代码实现
    • 1. 代码实现思路
    • 2. 实现代码

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

一、希尔排序原理

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

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

希尔3

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

希尔4

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

希尔5

二、希尔排序的相关问题

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

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

希尔6

希尔7

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

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

希尔8

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

希尔9

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

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处,即红色箭头处

希尔10

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

希尔11

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

希尔12

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

希尔13

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

希尔14

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

希尔15

希尔16

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

希尔17

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

希尔18

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

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 作为插入位置}}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/212147.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C++ 之命名空间namespace【详解】

文章目录 一&#xff0c;命名空间出现的意义二&#xff0c;命名空间的定义命名空间里面可以包含变量&#xff0c;函数&#xff0c;类型&#xff1a;命名空间不可以定义在局部作用域&#xff1a;命名空间可以嵌套&#xff1a; 三&#xff0c;同一个工程中允许存在多个相同名称的…

Axios 通过a标签下载文件 跨域下载

<!-- a标签占位 --><a ref"down" ></a>getTest() {this.$axios.request({url: https://cnv13.55.la/download?file_key3695fa9461a0ae59cf3148581e4fe339&handle_typeexcel2pdf,method: get,responseType: blob, // 切记类型 blob}).then(re…

语音识别技术在医疗行业中的应用案例

随着语音识别技术和计算机视觉技术的不断提高&#xff0c;现代医学正在进入全面数字化时代。 追求高质量的训练数据是人工智能产业的信条&#xff0c;得到更为精准的语音机器模型更离不开语音数据的不断供给。本文讲介绍: 什么是语音识别技术语音识别技术如何应用于医疗行业 …

shell 脚本的函数和数组

函数 —— 封装的一个公式&#xff1a;sin、cos、tan —— 函数为脚本的别名 —— 函数就是一个功能模块&#xff0c;在函数中写执行的命令即可&#xff1b;使用函数可以避免代码重复&#xff0c;增加可读性&#xff0c;简化脚本&#xff0c;使用函数可以将大的工程分割为若…

JSP过滤器和监听器

什么是过滤器 Servlet过滤器与Servlet十分相似&#xff0c;但它具有拦截客户端&#xff08;浏览器&#xff09;请求的功能&#xff0c;Servlet过滤器可以改变请求中的内容&#xff0c;来满足实际开发中的需要。 对于程序开发人员而言&#xff0c;过滤器实质就是在Web应用服务器…

九、ffmpeg命令转封装

开了几天小差&#xff0c;今天继续学习ffmpeg。 准备测试使用的视频&#xff0c;并查看其信息 # 查看视频信息。使用Mediainfo也可以 ffprobe test.mp4 视频格式的信息如下。 保持编码格式&#xff1a;ffmpeg -i test.mp4 -vcodec copy -acodec copy test_copy.tsffmpeg -i…

Unity地面交互效果——6、地形动态顶点置换和曲面细分

回到目录 Unity置换贴图局部距离曲面细分 大家好&#xff0c;我是阿赵。   这篇文章是我无聊的时候做了一个demo&#xff0c;觉得挺有趣&#xff0c;于是就发上来。这里面包含了4个内容&#xff1a;置换贴图、顶点偏移、局部曲面细分&#xff0c;曲面细分按距离调整强度。 …

Jmeter快速入门

文章目录 1.安装Jmeter1.1.下载1.2.解压1.3.运行 2.快速入门2.1.设置中文语言2.2.基本用法 1.安装Jmeter Jmeter依赖于JDK&#xff0c;所以必须确保当前计算机上已经安装了JDK&#xff0c;并且配置了环境变量。 1.1.下载 可以Apache Jmeter官网下载&#xff0c;地址&#xf…

Volcano3D绘制3D火山图

一边学习&#xff0c;一边总结&#xff0c;一边分享&#xff01; 本期教程内容 **注&#xff1a;**本教程详细内容 Volcano3D绘制3D火山图 一、前言 火山图是做差异分析中最常用到的图形&#xff0c;在前面的推文中&#xff0c;我们也推出了好几期火山图的绘制教程&#xff0…

ELK企业级日志分析平台——ES集群监控

启用xpack认证 官网&#xff1a;https://www.elastic.co/guide/en/elasticsearch/reference/7.6/configuring-tls.html#node-certificates 在elk1上生成证书 [rootelk1 ~]# cd /usr/share/elasticsearch/[rootelk1 elasticsearch]# bin/elasticsearch-certutil ca[rootelk1 ela…

windows下rust调试运行环境部署

1&#xff0c;rust编译环境安装 在联网环境下&#xff0c;建议使用rustup-init.exe程序安装&#xff08;本文使用的改模式) 选择1“默认"进行安装&#xff0c;默认安装x86_64-pc-windows-msvc 在安装完成后&#xff0c;后续为了配置gbd调试&#xff0c;也安装上x86_64-pc-…

AdaBoost提升分类器性能

目录 AdaBoost算法原理 AdaBoost工作详情 初始权重分配 第一轮 第二轮 后续轮次 最终模型 AdaBoost的API解释 AdaBoost 对房价进行预测 AdaBoost 与决策树模型的比较 结论 AdaBoost算法原理 在数据挖掘中&#xff0c;分类算法可以说是核心算法&#xff0c;其中 Ada…