【数据结构】八大排序之希尔排序算法

🦄个人主页:修修修也

🎏所属专栏:数据结构

⚙️操作环境:Visual Studio 2022


一.优化直接插入排序算法

我们在之前对直接插入排序算法的优化部分通过对直接插入排序的分析可以得到一个结论,即:

       进行直接插入排序的数组,如果越接近局部有序,则后续进行直接插入排序算法时其时间复杂度就会越低.

       所谓基本有序,就是指小的关键字基本在前面,大的关键字基本在后面,而不大不小的基本在中间.

       例如下面这个数组序列,虽然它还是无序的状态,甚至是局部逆序的状态,但至少它的前8个数据"0-7"都在前半部分,后8个数据"8-15"都在后半部分,这样就比完全逆序状态更接近基本有序,相应的算法执行的次数也直接减少了一半:

         当我们再进一步,将它们整合的更加接近局部有序一些,可以发现,这时算法的总执行次数又直接减少了一半:

        而当我们整合到最接近局部有序时,可以发现,这时算法的总执行次数表达式中的n^2项就已经消失了:


我们已经知道了如果将数组整合成局部有序,就可以大大优化直接插入排序,问题是如何通过预排序将数列整合成局部有序呢?

其实很简单,我们将这些数字不断分为gap组,然后分别让相隔gap个元素的一组数据保持有序就可以了:

         如下,第一次我们将数组分为8组,然后使相隔8个元素的每组数据都保持有序,即第一组数据"15和7"要调整为顺序,则将其二者调换位置即可,后续七组操作同理:

然后我们就可以得到如下数组了:

         接着,我们再将数组分为4组,让每隔4个元素的数据保持有序,即第一组数据"7,3,15,11"要调整为顺序,则将其看作一个代排数组,然后用直接插入排序将其调整为"3,7,11,15"的顺序,后面7组同理:

然后我们就可以得到如下数组:

         我们继续再将数组分为2组,让每隔2个元素的数据保持有序,即将第一组数据"3,1,7,5,11,9,15,13"直接插入排序,将其调整为"1,3,5,7,9,11,13,15"的顺序,第二组同理:

 然后我们就可以得到如下数组:

          然后就是最后一步,我们将数组看作一组,让相邻的两个元素的数据保持有序,即将全组数据直接插入排序,就可以得到最终结果:

至此,其实我们对直接插入排序的优化过程,就是希尔排序算法的思路.


二.希尔排序简介及思路

希尔排序(Shell Sort)是一种插入排序算法.

它的基本思想是:

  • 先选定一个整数,把待排序文件中所有数据分成gap个组,所有距离为gap的数据分在同一组内,并对每一组内的数据进行排序.
  • 重复上述分组和排序的工作,当达到gap=1时,所有数据在统一组内排好序.

算法动图演示如下:


三.希尔排序算法的代码实现

算法实现步骤:(以升序为例)

  1. 从下标为0的元素开始,遍历到下标为n-gap个元素为止,我们使用end来记录本次处理的元素下标,用tmp记录下间隔gap的元素的数值.
  2. 和间隔gap的两个元素进行比较,如果a[end+gap] < a[end],则将a[end]的值赋值给a[end+gap],并给end减掉gap.
  3. 然后无论这次有没有交换位置,都将tmp赋值给a[end+gap]的位置,如果没有交换,则a[end+gap]就是tmp原本的值,如果这次有交换,则因为end减去了gap,则会使tmp赋值给原本a[end]的位置.该部分图示如下:
  4. 当第一轮遍历完下标为n-gap的元素之后,给gap除以2,继续重复1-3步的操作.
  5. 不断重复第4步操作,直到最终gap为1,即执行直接插入排序后,本次排序完成.

搞清算法实现步骤后,代码实现就比较简单了,希尔排序代码如下:

//希尔排序(升序
void ShellSort(int* a, int n)
{
	int gap = n;
	//gap>1都是在预排序
	//gap==1时就是直接插入排序了

	while (gap > 1)
	{
		gap /= 2;
		//嫌慢的话可以gap/=3+1.加一是要保证最后一次一定是1

		for (int i = 0; i < n - gap; i++)
		{
			int end = i;
			int tmp = a[i + gap];
			while (end >= 0)
			{
				if (tmp < a[end])
				{
					a[end + gap] = a[end];
					end -= gap;
				}
				else
				{
					break;
				}
			}
			a[end + gap] = tmp;
		}
	}
}

四.希尔排序算法的时间复杂度分析

希尔排序的时间复杂度的计算是较为复杂的,我们先来看两本官方书籍对该部分的描述:

       希尔排序的分析是一个复杂的问题,因为它的时间是所取“增量”序列的函数,这涉及一些数学上尚未解决的难题。因此,到目前为止尚未有人求得一种最好的增量序列,但大量的研究已得出一些局部的结论。如有人指出,当增量序列为dlta[k]=2^{t-k+1}-1时,希尔排序的时间复杂度为O(n^{\frac{3}{2}}),其中t为排序趟数,1 \leqslant k \leqslant t \leqslant \left \lfloor log_{2}(n+1) \right \rfloor

        还有人在大量的实验基础上推出:当n在某个特定范围内,希尔排序所需的比较和移动次数约为n^{1.3},当n\rightarrow \infty时,可减少到n((log_{2}n)^{2})^{2}。增量序列可以有各种取法,但需注意:应使增量序列中的值没有除1之外的公因子,并且最后一个增量值必须等于1。

                                                                 ——《数据结构(C语言版)》严蔚敏

       gap的取法有多种。最初Shell提出取gap=\left \lfloor \frac{n}{2} \right \rfloorgap=\left \lfloor \frac{gap}{2} \right \rfloor,直到gap=1,后来Knuth提出取gap=\left \lfloor \frac{gap}{3} \right \rfloor+1。还有人提出都取奇数为好,也有人提出各gap互质为好。无论哪一种主张都没有得到证明。
        对希尔排序的时间复杂度的分析很困难,在特定情况下可以准确地估算关键码的比较次数和对象移动次数,但想要弄清关键码比较数和对象移动次教与增量选择之间的依赖关系,并给出完整的数学分析,还没有人能够做到。在Knuth所著的《计算机程序设计技巧》第3卷中,利用大量的实验统计资料得出,当n很大时,关键码平均比较次数和对象平均移动次数大约在n^{1.25}1.6n^{1.25}范围内,这是在利用直接插入排序作为子序列排序方法的情况下得到的。                          
  ——《数据结构-用面向对象方法与C++描述》殷人昆

       因此,当前对于希尔排序的时间复杂度,学术界仍没有一个确切的研究结果,我们只能在估算希尔排序时间复杂度时借助Knuth大佬的实验统计结果,即采用O(n^{1.25})O(1.6*n^{1.25})近似的估算希尔排序的时间复杂度.


结语

希望这篇希尔排序算法详解能对大家有所帮助,欢迎大佬们留言或私信与我交流.

有关更多排序相关知识可以移步:

【数据结构】八大排序算法​icon-default.png?t=N7T8https://blog.csdn.net/weixin_72357342/article/details/135038495?csdn_share_tail=%7B%22type%22%3A%22blog%22%2C%22rType%22%3A%22article%22%2C%22rId%22%3A%22135038495%22%2C%22source%22%3A%22weixin_72357342%22%7D&fromshare=blogdetail学海漫浩浩,我亦苦作舟!关注我,大家一起学习,一起进步!

相关文章推荐

【数据结构】八大排序之冒泡排序算法

【数据结构】八大排序之希尔排序算法


数据结构排序算法篇思维导图:


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

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

相关文章

软件设计师——计算机组成原理(三)

&#x1f4d1;前言 本文主要是【计算机组成原理】——软件设计师——计算机组成原理的文章&#xff0c;如果有什么需要改进的地方还请大佬指出⛺️ &#x1f3ac;作者简介&#xff1a;大家好&#xff0c;我是听风与他&#x1f947; ☁️博客首页&#xff1a;CSDN主页听风与他 …

计算机网络:运输层

0 本节主要内容 问题描述 解决思路 1 问题描述 1.1 知识回顾 利用如下拓扑对前面的知识进行回顾。 图1 拓扑图 问题&#xff1a;源主机 H 1 \textrm{H}_1 H1​要和目的主机 H 2 \textrm{H}_2 H2​进行通信&#xff0c;源主机 H 1 \textrm{H}_1 H1​要构建数据包封装来自应…

SQL进阶理论篇(九):为什么不存在完美的索引

文章目录 简介索引片和过滤因子如何通过宽表避免回表什么是过滤因子理想索引设计&#xff1a;三星索引为什么很难存在理想的索引设计&#xff1f;参考文献 简介 本节将主要介绍以下部分&#xff1a; 什么是索引片&#xff0c;什么是过滤因子&#xff1f;设计索引的时候&#…

1847_MOSFET预驱以及作用

Grey 全部学习内容汇总&#xff1a;GitHub - GreyZhang/g_hardware_basic: You should learn some hardware design knowledge in case hardware engineer would ask you to prove your software is right when their hardware design is wrong! 1847_MOSFET预驱以及作用 MO…

5分钟部署你的第一个K8S应用

查看k8s集群信息 kubectl cluster-info查看节点信息 kubectl get node查看内部组件 kubectl get pod -A部署第一个K8S应用-Nginx&#xff0c;并通过公网ip访问 创建deployment&#xff08;Pod控制器的一种, 直接删除pod后&#xff0c;会自动创建新的&#xff0c;需要删除de…

黑马头条--day02.文章列表查看

目录 一.分表 1.导入数据库sql脚本 2.导入实体类 3.分表规则 二.文章列表接口 (1)思路 2)接口定义 3)功能实现 1.1)&#xff1a;导入heima-leadnews-article微服务&#xff0c;资料在当天的文件夹中 1.2)&#xff1a;定义接口 1.3)&#xff1a;编写mapper文件 1.4)&…

Support Vector Machine(SVM)——支持向量机

1.从逻辑回归到SVM 回顾一下逻辑回归的模型 然后经过sigmoid函数得到预测y1的概率&#xff0c;sigmoid函数如下图 对于单个样本来说损失函数如下 当一个输入的真实标签为1时&#xff0c;损失函数就只剩&#xff0c;如左图所示,我们想要让&#xff0c;来使损失函数尽可能的小 对…

重新认识Word——尾注

重新认识Word——尾注 参考文献格式文献自动生成器插入尾注将数字带上方括号将参考文献中的标号改为非上标 多处引用一篇文献多篇文献被一处引用插入尾注有横线怎么删除&#xff1f;删除尾注 前面我们学习了如何给图片&#xff0c;公式自动添加编号&#xff0c;今天我们来看看毕…

【TB作品】51单片机读取重量和液位,OLED显示

代码打开下载&#xff1a; http://dt4.8tupian.net/2/28880a64b6666.pg3这段代码是为微控制器编写的&#xff0c;可能是基于8051架构&#xff0c;使用Keil C51编译器。该代码结合了OLED显示器、超声波距离传感器和基于HX711的称重传感器的功能。以下是主要组件及其功能的详细说…

海洋可视化大屏,Photoshop源文件

数据大屏通过实时的数据展示&#xff0c;可及时发现数据的变化和异常&#xff0c;以便及时采取措施。现分享海洋动力大数据监控、海洋数据监控系统、科技感海洋监控系统大屏模版的UI源文件&#xff0c;供UI设计师们快速获取PSD源文件完成工作 若需更多 大屏组件&#xff0c;请…

1852_bash中的find应用扩展

Grey 全部学习内容汇总&#xff1a; https://github.com/GreyZhang/toolbox 1852_bash中的find应用扩展 find这个工具我用了好多年了&#xff0c;但是是不是真的会用呢&#xff1f;其实不然&#xff0c;否则也不会出现这种总结式的笔记。其实&#xff0c;注意部分小细节之后…

电子学会C/C++编程等级考试2021年09月(六级)真题解析

C/C++等级考试(1~8级)全部真题・点这里 第1题:双端队列 定义一个双端队列,进队操作与普通队列一样,从队尾进入。出队操作既可以从队头,也可以从队尾。编程实现这个数据结构。 时间限制:1000 内存限制:65535输入 第一行输入一个整数t,代表测试数据的组数。 每组数据的…

国内最好的开源MES/免费MES/低代码MES

一、系统概述&#xff1a; 万界星空科技免费MES、开源MES、商业开源MES、市面上最好的开源MES、MES源代码、适合二开的开源MES、功能最全的开源MES、好看的数字大屏、开源自动排班系统、开源质检系统。 1.万界星空开源MES制造执行系统的Java开源版本。 开源mes系统包括系统管…

re:Invent2023大会隆重推出自研芯片Graviton4和Trainium2

目录 一、前言 二、体验Graviton系列产品 &#xff08;一&#xff09;创建普通的EC2实例 &#xff08;二&#xff09;创建Graviton处理器的EC2实例 &#xff08;三&#xff09;远程到服务器 方式1&#xff1a;创建成功时连接 方式2&#xff1a;SSH客户端 方式3&#xff1a;正确…

01--二分查找

一. 初识算法 1.1 什么是算法&#xff1f; 在数学和计算机科学领域&#xff0c;算法是一系列有限的严谨指令&#xff0c;通常用于解决一类特定问题或执行计算 不正式的说&#xff0c;算法就是任何定义优良的计算过程&#xff1a;接收一些值作为输入&#xff0c;在有限的时间…

【LeetCode:746. 使用最小花费爬楼梯 | 递归 -> 记忆化搜索 -> DP】

&#x1f680; 算法题 &#x1f680; &#x1f332; 算法刷题专栏 | 面试必备算法 | 面试高频算法 &#x1f340; &#x1f332; 越难的东西,越要努力坚持&#xff0c;因为它具有很高的价值&#xff0c;算法就是这样✨ &#x1f332; 作者简介&#xff1a;硕风和炜&#xff0c;…

Python基础08-文件操作详解

零、文章目录 Python基础08-文件操作详解 1、文件操作概述 &#xff08;1&#xff09;文件是什么 内存中存放的数据在计算机关机后就会消失。要长久保存数据&#xff0c;就要使用硬盘、光盘、U 盘等设备。为了便于数据的管理和检索&#xff0c;引入了**“文件”**的概念。 …

【普中】基于51单片机简易计算器显示设计( proteus仿真+程序+设计报告+实物演示+讲解视频)

目录标题 &#x1f4df;1. 主要功能&#xff1a;&#x1f4df;2. 讲解视频&#xff1a;&#x1f4df;3. 设计说明书(报告)&#x1f4df;4. 仿真&#x1f4df;5. 实物烧录和现象&#x1f4df;6. 程序代码&#x1f4df;7. 设计资料内容清单 【普中开发板】基于51单片机简易计算器…

nodejs+vue+微信小程序+python+PHP校园二手交易系统的设计与实现-计算机毕业设计推荐

(2)管理员 进行维护&#xff0c;以及平台的后台管理工作都依靠管理员&#xff0c;其可以对信息进行管理。需具备功能有&#xff1b;首页、个人中心、学生管理、物品分类管理、物品信息管理、心愿贴、系统管理、订单管理等功能。系统分成管理员控制模块和学生模块。 本系统有良好…