插入排序⁻⁻⁻⁻直接插入排序希尔排序

引言

所谓的排序,就是使一串记录按照其中的某个或某些关键字的大小,递增或递减的排列起来的操作。

常见的排序算法有:

e3e60e163ea7413f838b5726d259905c.png

 今天我们主要学习插入排序的直接插入排序和希尔排序。

直接插入排序

什么是直接插入排序?

直接插入排序其实是一种很简单的排序算法哦。它就像我们平时整理扑克牌一样,一张一张地来,把每一张牌都插到已经排好序的部分里面,直到全部都排好。

25e59251b7514f12b92286c26ea56488.jpg

 我们再通过一个动图理解一下:

d9a74a8eea15476ab53c4a67b1f13c59.gif

思路

  1. 从第二个元素始,逐一遍历数组。
  2. 当前元素与前序已排序元素逐一比较,找到插入位置。
  3. 插入当前元素至正确位置,前序元素后移。
  4. 重复上述步骤,直至数组全排序。

代码

void insertSort(int* a, int n)
{
	for (int i = 1; i < n; i++) {
		int curIndex = i - 1, tmp = a[i];
		while (curIndex >= 0) {
			if (tmp < a[curIndex]) {
				a[curIndex + 1] = a[curIndex];
				--curIndex;
			}
			else {
				break;
			}
		}
		a[curIndex + 1] = tmp;
	}
}

时间复杂度

从代码我们可以看出,直接插入排序的时间复杂度是 O(n²),在数据比较少或者已经部分有序的情况下,它的性能还是不错的。

希尔排序

什么是希尔排序?

希尔排序,又称为缩小增量排序,是直接插入排序的一种更高效的改进版本。

前面我们知道,直接插入排序比最差的条件下时间复杂度可以达到O(n²),但是在部分有序的情况下,它的性能还是不错的。

希尔排序的基本思想是预排序,即先将数组内的数据变得部分有序,最后再通过直接插入排序将部分有序的数组进组排序。

那它具体是如何实现预排序的呢?接下来我们会进行讲解。

讲解与分析

接下来,我们具体来通过一个例子来理解一下希尔排序:先将整个待排序数组分割成若干个子序列(也称为分组),使得每个子序列中的元素在原数组中的位置间隔gap,然后对每个子序列分别进行直接插入排序,这样可以使原数组变得部分有序。我们一起来看一下:

原数组:int a[]={9,1,2,5,7,4,8,6,3,5};

接下来我们按照间隔(gap)为3时将原数组进行升序排序,什么意思呢?即下标为0,3,6,9的树为一组进行排序,对应上面的数组也就是将9,5,8,5进行排序:

5579b018902a40e68b9beac14d0ea6ec.png

 

tmp之前的数据已经按升序排序,开始进入下一轮排序:

fe848e964700402d8b947fddcca138c5.png

 

tmp之前的数据已经按升序排序,开始进行下一轮排序:

17f71b1b965e438d841c3e6e46f9e32d.jpg

如果我们让gap为2,原数组排序下来会是这样的:1cefbaf4c52c40228cc8cd13e1beeea7.png

 我们发现,gap越大,排序就越快,但是越不接近有序;gap越小,排序就越慢,但是越接近有序。

当gap等于1就是直接插入排序,gap大于1就是预排序。

那我们可以先让gap初始化为较大的数,我们可以逐渐缩小gap,再对新的子序列进行直接插入排序,直到最后增量减至1,此时整个数组几乎已经有序,最后再进行一次直接插入排序即可完成排序。

这里补充说明一下gap的初始值,一般初始化为数组长的一半或三分之一。如果是数组长度的二分之一,每次gap就是按照gap/=2去缩小;如果是数组长的三分之一,每次gap就是按照gap=gap/3+1去缩小(为什么不是gap/=3呢?我们要考虑到两个整数相除时,最后结果会向下取整,如果数组长度n=6,第一次排序时gap=n/3=2,第二次排序时gap/=3就是2/3=0,那这样下去永远都无法让gap==1,也就无法进行直接插入排序。所以应该是gap=gap/3+1)。

代码

void shellSort(int* a, int n)
{
	int gap = n;
	while (gap > 1) {
		gap = gap / 3 + 1;
		for (int i = 0; i < n - gap; i += gap) {
			int curIndex = i, tmp = a[i + gap];
			while (curIndex >= 0) {
				if (tmp < a[curIndex]) {
					a[curIndex + gap] = a[curIndex];
					curIndex -= gap;
				}
				else {
					break;
				}
			}
			a[curIndex + gap] = tmp;
		}
	}
	
}

时间复杂度

分析

  • 最外层循环:控制间隔(gap)的变化,通常从数组长度n开始,每次除以一个常数(如3)并加1,直到gap为1。此循环的时间复杂度为O(logn)。
  • 内层循环(这种分析方式存在一定不严谨性):包括两层循环,一层用于遍历数组,另一层用于在分组内进行插入排序。for循环以gap为步长遍历数组,因此其迭代次数为n / gap次。在每次for循环的迭代中,while循环负责将当前元素(位于i + gap位置)插入到其前面gap间隔的有序子序列中。最坏情况下,这个插入操作需要比较和移动gap个元素(但实际上由于分组的存在,通常不会达到这么多)。然而,对于时间复杂度的分析,我们可以认为每次while循环至多执行O(gap)次操作,但在整个for循环中,由于分组的存在,每个元素至多被比较和移动一次。因此,对于每个固定的gap值,内层循环(包括for和while)的总时间复杂度为O(n)。

注意:严谨的内层循环时间复杂度分析

1.gap较大时:

  • 当gap较大时,数组被分成较少的组,每组包含较多的元素。
  • 由于此时数组尚未排序,每组内的插入排序可能需要进行较多的比较和交换。
  • 但由于组数较少,整体时间复杂度相对较低。

2.gap逐渐减小时:

  • 随着gap的减小,数组被分成更多的组,每组包含的元素减少。
  • 由于前面的排序过程,数组已经逐渐接近有序状态,因此每组内的插入排序所需的比较和交换次数减少。
  • 此时,虽然组数增多,但每组内的排序工作量减少,整体时间复杂度仍然保持较低水平。

3.gap变化过程中的复杂度峰值:

  • 在gap从大到小变化的过程中,存在一个复杂度峰值。这是因为当gap处于某个中间值时,数组既没有被完全分组(如gap很大时),也没有接近有序(如gap很小时)。
  • 在这个峰值点,每组内的插入排序可能需要较多的比较和交换,导致时间复杂度相对较高。

综合时间复杂度

希尔排序的时间复杂度不是简单的O(nlogn),因为间隔的变化会影响排序的效率。

在某些情况下,希尔排序的时间复杂度可以接近O(nlogn),特别是在数组已经部分有序或间隔选择得当的情况下。

然而,在最坏情况下,希尔排序的时间复杂度可能更高,一些研究表明其时间复杂度在O(n^1.25)到O(n^1.6)之间,通常可以简化为O(n^1.3)。

 

 

 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

基于Springboot + Vue开发的飞驰驾校预约学习平台(项目源码 + lw)

一、功能介绍 飞驰驾校预约学习平台包含管理员、教练、用户三个角色以及前后台系统。 主要功能 前台系统功能 首页展示、理论考试、教练信息、教练预约、学习资料、学习视频观看、用户留言、公告信息展示、个人中心信息管理 后台系统功能 管理员或用户登录成功后&#xff0c…

【vivado】时序报告--best时序和worst时序

利用vivado进行开发时&#xff0c;生成best时序报告和worst时序报告。 best时序报告 slow选择min_max&#xff0c;fast选择none。 worst时序报告 fast选择min_max&#xff0c;slow选择none。

深度学习GPU显卡4060ti与4060有什么区别?又与游戏显卡有什么区别?

深度学习GPU显卡4060 Ti与4060的区别 &#xff1a; 性能差异 &#xff1a; 4060 Ti : 4060 Ti通常比4060更强大&#xff0c;具有更多的CUDA核心和更高的显存带宽&#xff0c;因此在计算密集型任务&#xff08;如深度学习训练和推理&#xff09;中表现更好。其显卡核心频率、CUD…

李飞飞:Agent AI 多模态交互的前沿探索

发布于:2024 年 11 月 27 日 星期三 北京 #RAG #李飞飞 #Agent #多模态 #大模型 Agent AI在多模态交互方面展现出巨大潜力,通过整合各类技术,在游戏、机器人、医疗等领域广泛应用。如游戏中优化NPC行为,机器人领域实现多模态操作等。然而,其面临数据隐私、偏见、可解释性…

leetcode 3001. 捕获黑皇后需要的最少移动次数 中等

现有一个下标从 1 开始的 8 x 8 棋盘&#xff0c;上面有 3 枚棋子。 给你 6 个整数 a 、b 、c 、d 、e 和 f &#xff0c;其中&#xff1a; (a, b) 表示白色车的位置。(c, d) 表示白色象的位置。(e, f) 表示黑皇后的位置。 假定你只能移动白色棋子&#xff0c;返回捕获黑皇后…

bash命令缓存导致命令执行失败的问题

1、问题背景 为了修复老版本 vsftpd 的安全漏洞&#xff0c;需要把生产环境上 vsftpd 版本升级到 vsftpd-3.0.5&#xff0c;因为直接使用 rpm 包的方式进行升级还涉及到下层依赖包的升级(生产环境上的依赖包版本不能随意变更&#xff0c;可能会影响其他上层应用)&#xff0c;所…

Docker部署的gitlab升级的详细步骤(升级到17.6.1版本)

文章目录 一、Gitlab提示升级信息二、老版本的docker运行gitlab命令三、备份老版本Gitlab数据四、确定升级路线五、升级(共分3个版本升级)5.1 升级第一步(17.1.2 > 17.3.7)5.2 升级第二步(17.3.7 > 17.5.3)5.3 升级第三步(17.5.3 > 17.6.1) 六、web端访问gitlab服务 一…

Spring03——基于xml的Spring应用

Spring开发中主要对Bean的配置 Bean的常用配置一览如下&#xff1a; Xml配置方式功能描述<bean id"" class"">Bean的id和全限定名配置<bean name"">通过name设置Bean的别名&#xff0c;通过别名也能直接获取到Bean实例<bean sc…

源码可运行-PHP注册登录源码,PHP实现登陆后才能访问页面

最近有一个项目需要实现会员注册和页面登陆后才能访问&#xff0c;所以简单的HTML是无法实现的&#xff0c;就必须通过PHP、html和Mysql来实现&#xff0c;先给大家看一下登录和注册页的效果图。&#xff08;注册完成后会自动跳转到登录窗口&#xff0c;即使A用户登陆后分享了网…

使用Goland对6.5840项目进行go build出现异常

使用Goland对6.5840项目进行go build出现异常 Lab地址: https://pdos.csail.mit.edu/6.824/labs/lab-mr.html项目地址: git://g.csail.mit.edu/6.5840-golabs-2024 6.5840运行环境: mac系统 goland git clone git://g.csail.mit.edu/6.5840-golabs-2024 6.5840 cd 6.5840/src…

35页PDF | 元数据与数据血缘落地实施(限免下载)

一、前言 这份报告详细介绍了元数据与数据血缘的概念、重要性以及在企业数据中台中的应用。报告阐述了数据中台的核心价值在于整合和管理体系内的数据&#xff0c;以提升数据资产化能力并支持业务决策。报告还涵盖了元数据的分类&#xff08;技术元数据和业务元数据&#xff0…

【Flink】Flink Checkpoint 流程解析

Flink Checkpoint 流程解析 Checkpoint 流程解析 Flink Checkpoint 流程解析Checkpint 流程概括Checkpoint 触发流程解析 (Flink 1.20)任务启动后 JobManager 开始定期对任务执行 CheckpointJobManager 使用 CheckpointCoordinator 触发 CheckpointCheckpointCoordinator 初始化…

vue3项目最新eslint9+prettier+husky+stylelint+vscode配置

一、eslint9和prettier通用配置 安装必装插件 ESlint9.x pnpm add eslintlatest -DESlint配置 vue 规则 , typescript解析器 pnpm add eslint-plugin-vue typescript-eslint -DESlint配置 JavaScript 规则 pnpm add eslint/js -D配置所有全局变量 globals pnpm add globa…

MacOS安装软件后无法启动报错:“已损坏,无法打开,你应该将它移到废纸篓“

目录 报错截图 解决方法 知识科普 报错截图 解决方法 1. 打开系统设置->安全性与隐私->选择任何来源 2. 如果打开没有看到"任何来源"&#xff0c;如果不开启“任何来源”的选项&#xff0c;会直接影响到无法运行的第三方应用。开启“任何来源”的方法如下&a…

C++ STL 容器系列(三)list —— 编程世界的万能胶,数据结构中的百变精灵

STL系列学习参考&#xff1a; C STL系列__zwy的博客-CSDN博客https://blog.csdn.net/bite_zwy/category_12838593.html 学习C STL的三个境界&#xff0c;会用&#xff0c;明理&#xff0c;能扩展&#xff0c;STL中的所有容器都遵循这个规律&#xff0c;下面我们就按照这三个境…

Hive分区值的插入

对于Hive分区表&#xff0c;在我们插入数据的时候需要指定对应的分区值&#xff0c;而这里就会涉及很多种情况。比如静态分区插入、动态分区插入、提供的分区值和分区字段类型不一致&#xff0c;或者提供的分区值是NULL的情况&#xff0c;下面我们依次来展现下不同情况下的表现…

Python数据分析Matplotlib(一):文本说明

目录 1.1 使用matplotlib.pyplot中的title()函数设置图像标题1.2 使用matplotlib.pyplot中的annotate()函数标注文字1.3 使用matplotlib.pyplot中的text()函数设置文字说明1.4 使用matplotlib.pyplot中的legend()函数和plot中的label参数一起作用添加图例1.5 使用matplotlib.py…

AUTO TECH China 2025 华南展:探索汽车技术的新纪元

AUTO TECH China 2025 华南展&#xff1a;探索汽车技术的新纪元 随着科技的日新月异&#xff0c;汽车行业正经历着前所未有的变革。从电动化、智能化到网联化&#xff0c;每一项新技术的应用都在重塑我们对汽车的认知。为了展示这些令人激动的创新成果&#xff0c;我们荣幸地宣…

3D 生成重建017-StyleGaussian用文本或图像对你的3DGS内容进行风格迁移

3D 生成重建017-StyleGaussian用文本或图像对你的3DGS内容进行风格迁移 文章目录 0 论文工作1 论文方法2 实验结果 0 论文工作 论文 “StyleGaussian: Instant 3D Style Transfer with Gaussian Splatting” 介绍了一种新颖的3D风格迁移方法 StyleGaussian&#xff0c;该方法通…

微信小程序提交测试版,但是扫描体验版的二维码 显示 页面不存在

检查路径首页是否和我们微信小程序中的首页路径一致。 显然我的不一致。 {"pagePath": "pages/index/index","text": "产品","iconPath": "icons/Group 450.png","selectedIconPath": "/icons/组 …