排序算法之【希尔排序】

news2024/11/23 12:57:51

📙作者简介: 清水加冰,目前大二在读,正在学习C/C++、Python、操作系统、数据库等。

📘相关专栏:C语言初阶、C语言进阶、C语言刷题训练营、数据结构刷题训练营、有感兴趣的可以看一看。

欢迎点赞 👍 收藏 ⭐留言 📝 如有错误还望各路大佬指正!

✨每一次努力都是一种收获,每一次坚持都是一种成长✨       

在这里插入图片描述

 前言

        希尔排序,作为一种高效的排序算法,更是在排序算法这个舞台上展现出了自己独特的魅力,听这个名字就感觉这个排序不简单,本篇文章我将带领大家深入了解希尔排序。


1. 排序算法

         在数据世界中,排序算法是一种强大的工具,能够将混乱无序的数据变得井然有序,排序算法有很多种,最常见也是最常用的排序算法有8种,本期的主角是希尔排序。

1.1插入排序

         希尔排序属于插入排序的一种,在理解希尔排序之前,我们需要先来了解一下插入排序的初阶——直接插入排序

 1.1.1 直接插入排序

         直接插入排序的原理非常好理解,举个例子:我们在完扑克牌时都会对牌的大小进行排序(也就是组成顺子)。

         这就利用了直接直接插入排序,7和10比较,7小,7再和5比较,比5大,所以7就插入到10的前边。

        直接插入排序,是一种简单直观的排序算法,它的基本思想是将一个待排序的元素插入到已经排好序的元素序列中的适当位置,从而得到一个新的、个数加一的有序序列。具体步骤如下:

  1. 将待排序序列第一个元素视为已排序序列,将其作为比较的基准。
  2. 从第二个元素开始,依次将每个元素插入到已排序序列中的适当位置。
  3. 每次插入一个元素时,都将该元素与已排序序列中的元素进行比较,找到合适的位置插入。
  4. 插入时,将已排序序列中比待插入元素大的元素向后移动一位,为待插入元素腾出位置。
  5. 重复步骤3和步骤4,直到将所有元素插入到已排序序列中。

 过程如下图:

         理解了基本原理,我们来进行代码实现,在写排序算法时我们可以先写一趟的逻辑。我们需要记录开始比较的位置,还要记录开始位置的后一个数据,例如当end=0时,我们需要记录end的后一个位置数据,从end开始一次向前移动并比较大小。如果tmp小于end位置的数据,那么,end位置的数据就向后移动一个位置。在这个过程中end要不断减减。具体代码如下:

	int end = ;
	int tmp = arr[end + 1];
	while (end >= 0)
	{
		if (tmp < arr[end])
		{
			arr[end + 1] = arr[end];
			
		}
		else
		{
			break;
		}
		end--;
	}
	arr[end + 1] = tmp;//找到比tmp大的数据后跳出循环插入到end的后边
}

        这也仅仅是一个数据插入的过程,接下来我们要搞定这个数组的插入。我们可以利用一个for循环,观察动图我们可以发现,end是逐个向后的。但我们需要考虑越界的问题,i要小于n-1,结束位置在最后的前一个位置。完整代码如下:

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

 1.1.2 希尔排序

 由来

        通过上述的插入排序过程我们可以发现,插入排序的时间复杂度不低,在局部有序的情况下,插入排序很优。但存在最坏的情况,就是逆序。逆序的情况下,它的时间复杂度不亚于冒泡排序。

        为了防止出现较坏的情况,有位叫希尔的大佬对插入排序进行了优化,就是在插入排序之前进行预排序。所以希尔排序的过程就可分为两部分:

  1. 预排序
  2. 插入排序
 过程

      希尔排序(Shell Sort),也称为缩小增量排序,是插入排序的一种改进算法。它通过将待排序序列分割成若干子序列来进行排序,最终将整个序列排序。

        希尔排序的基本思想是先将待排序序列按照一定的增量进行分组,对每个子序列进行插入排序,然后逐步缩小增量,再次进行分组和插入排序,直到增量为1,完成最后一次插入排序,整个序列就变成有序的。

  预排序     

         上边说到按照增量进行分组,不好理解,我们可以理解为步数(gap),当gap为1的时候就是插入排序,gap为1就是相邻数据依次比较进行插入。当gap > 1时都是预排序,目的是让数组更接近于有序。

        例如gap等于4,那进行比较时就是对相邻间隔为4的数据进行调整位置插入。如下图:

 gap越小,数据就越接近有序。

 1.1.3 希尔排序的实现

         理解了预排序的原理,我们可以先来写一下预排序。

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

        这段代码看着是否很熟悉,当gap为1时,这段代码就是直接插入排序。这个是从第一个数据开始,将数组中距离为gap数据进行调整。

        那么接下来还要从第二个数据开始,将距离为gap的数据进行调整。所以这里我们可以加一个循环,确保每个数据都能被调整。

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

这里我们可以优化一下,我们这样写:

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

        大多数看到的书中都是这样写的,或许在之前学习中,很多同学不懂for循环这里为什么这样写。起初的逻辑是,调整完一组后,再调整下一组。那我们可不可以同时调整所有组?

我们先调整第一个数据和它距离为gap的数据,不急着将整组数据调整完,接着开始从第二个数据开始与它距离为gap的数据进行调整……

         理解了这里,我们继续,上述的过程是在gap不变的情况下进行的,预排序的过程是不断的改变gap的值来进行预排序。gap越小预排序后数据越接近有序。

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

	}
}

         我们可以先令gap等于n(数组的数据个数),然后使用while循环判断gap是否大于1,当gap > 1时都是预排序,进入while循环之后,gap就整除2。到这里希尔排序就实现了。任何一个大于2的数除2最后都等于1,除到最后gap等于2时进入while循环,先执行gap=gap/2,最后一次执行时就刚好是插入排序。

         当然gap也不一定就除2,在一些书中也有这样的写法:gap=gap/3+1,除3是因为有人觉得gap/2进行预排序的次数太多了,但gap/3并不能保证除到最后,所以就有了这种写法:gap=gap/3+1。

2. 复杂度

        了解了直接插入排序和希尔排序,那我们就来说一说它的复杂度问题,它们的空间复杂度都为O(1),重点就在它们的时间复杂度。

2.1  直接插入排序

         直接插入排序的时间复杂度好说,假设有n个数据,第一次从第一个数据开始,最多比较1次,第二次从第二个数据开始,最多比较2次,第三个最多比较3次……

那么它的执行次数T=1+2+3+4+……+n-1,等差数列求和,T=(n-1+1)*n/2(首项加尾项乘以项数除以2)所以它的时间复杂度最差达到O(N^2)。

2.2  希尔排序

         希尔排序的时间复杂度计算非常复杂,它的时间复杂度和gap有关。

当gap很大时,例如gap=n/3。整个数组逆序那么就有n/3组数据,每组数据最多比较3(1+2)次。

 合计比较:n/3*3=n。

 当gap等于n/9时,整个数组逆序,就会有n/9组数据,每组有9个数据,每组最多比较(1+2+3+4+5+6+7+8)次

 合计比较:n/9*36=4n。

 当gap很小时,如gap等于1时,就只有1组数据进行调整排序,此时的数据已经非常接近有序了,再进行调整,最差会比较n次,估算一下,合计:n

 由此可以看出:希尔排序的性能图形为一个曲线函数。

希尔排序时间复杂度计算分析,以上内容为了解

         希尔排序的时间复杂度不好计算,因为gap的取值方法很多,导致很难去计算,因此在很多书中给出的希尔排序的时间复杂度都不固定。在实际测试效果时,众多答案中,最符合的是O(N^1.3)。从这里就可以看出,希尔排序它非常的不稳。


总结 

         本篇文章主要介绍了希尔排序,希尔排序的时间复杂度与增量序列的选择有关,它是一种不稳定的排序算法,适用于中等规模的数据排序。希望本文对你有所帮助,最后,感谢阅读!

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【ROS 2】-2 话题通信

飞书原文链接&#xff1a; Docs

文件的随机读写函数:ftell rewind

目录 函数介绍&#xff1a; ftell&#xff1a; 函数原型&#xff1a; 举例&#xff1a; 文件内容展示&#xff1a; 代码操作&#xff1a; 结果&#xff1a; rewind&#xff1a; 函数原型&#xff1a; 举例&#xff1a; 文件内容展示&#xff1a; 代码操作&#xff1…

JOSEF约瑟 静态中间继电器JZY-402 JZJ-404 AC220V 触点形式两开两闭

系列型号&#xff1a; JZY(J)-400静态中间继电器 JZ-Y-401静态中间继电器JZ-Y-402静态中间继电器 JZ-Y-403静态中间继电器JZ-Y-404静态中间继电器 JZ-Y-405静态中间继电器JZ-Y-406静态中间继电器 JZ-Y-407静态中间继电器JZ-Y-408静态中间继电器 JZ-Y-409静态中间继电器JZ…

10kv后台配电监控系统

10kv电力系统应用广泛&#xff0c;在各行各业都发挥着举足轻重的作用&#xff0c;其运行状态直接影响到电力系统的稳定性和可靠性。 一、系统概述 10kV后台配电监控系统是指对10kV配电系统的各种设备进行实时监控、调节、保护、控制和调节的现代化管理系统。通过在电力…

找高清、4K图片素材就上这6个网站,免费下载!

不会还有人找图片素材直接上网去搜吧&#xff0c;告诉你们6个网站&#xff0c;轻松找到想要的图片素材&#xff0c;不仅质量高&#xff0c;还可以免费下载&#xff0c;重点是还可以商用。赶紧收藏起来吧~ 1、菜鸟图库 https://www.sucai999.com/pic.html?vNTYwNDUx 网站主要为…

挺进欧洲:中国汽车如何破解品牌与成本双重困境?

摘要&#xff1a;2022年&#xff0c;中国超越德国&#xff0c;跻身全球第二大汽车出口大国&#xff0c;仅次于日本。历经国内市场的激烈竞争和技术积累,中国汽车品牌凭借在新能源技术上的优势和制造力,决定挑战欧洲-BBA(奔驰、宝马、奥迪)的主场。令人惊讶的是,尽管在21世纪初,…

全链路压测:优化系统性能的关键措施

在现代互联网时代&#xff0c;系统的性能稳定性和可靠性对于企业的成功至关重要。全链路压测作为一项关键的测试措施&#xff0c;可以模拟真实的负载情况&#xff0c;全面评估系统在高负载环境下的表现。本文将介绍全链路压测的定义、作用以及在优化系统性能方面的重要性。 一、…

基于R做宏基因组进化树+丰度柱状图TreeBar带聚类树的堆叠柱形图

写在前面 同之前一样&#xff0c;重分析需要所以自己找了各路代码借鉴学习&#xff0c;详情请参考 R语言绘制带聚类树的堆叠柱形图 &#xff0c; 实操效果如下&#xff1a; 步骤 表格预处理 选取不同样本属水平的物种丰度图&#xff08;绝对和相对水平都可以&#xff0c;相对…

Spring实现简单的Bean容器

1.BeanDefinition&#xff0c;用于定义 Bean 实例化信息&#xff0c;现在的实现是以一个 Object 存放对象 public class BeanDefinition {/*** bean对象*/private Object bean;/*** 存放 &#xff08;定义&#xff09;Bean 对象*/public BeanDefinition(Object bean) {this.bea…

RFID用于仓库盘点,省时省力

RFID用于仓库盘点&#xff0c;省时省力 RFID技术已经被广泛应用在工业制造和日常生活当中。它使用射频信号来识别和跟踪标签中的信息。RFID系统由两个主要组件组成&#xff1a;RFID标签和RFID读写器。RFID标签通常由一个芯片和一个天线组成。标签内的芯片存储着特定的数据&…

监控员工聊天记录违法吗?监控员工聊天记录软件

在现代社会&#xff0c;企业面临着如何确保员工工作效率和质量的挑战。为了解决这一问题&#xff0c;一些企业选择监控员工的聊天记录&#xff0c;以确保他们遵守公司规定&#xff0c;不泄露敏感信息&#xff0c;以及避免工作效率低下。然而&#xff0c;这种做法是否合法呢&…

阿里巴巴K8S集成seata

正文 在K8S集成seata&#xff0c;官方配置 代码 apiVersion: v1 kind: Service metadata:name: seata-servernamespace: wmz-devlabels:k8s-app: seata-server spec:type: NodePortports:- port: 8091nodePort: 30091protocol: TCPname: httpselector:k8s-app: seata-server-…

适合中小企业的推荐佳企业备份软件

企业环境通常比单个工作站拥有更多的机器、更多的数据和更多的人员&#xff0c;这些可能会带来更多的潜在风险——96%的企业经历过至少一种数据丢失的主要原因&#xff1a;人为错误、系统崩溃、硬件故障、病毒袭击、停电、火灾和自然灾害。 数据丢失对企业造成的损害不仅在…

Rhino犀牛技巧[导出DXF给AD]

导出DXF给AD 按照默认的方式导出,在AD会缺失线: 导出的事后选择"2004 直线" 这时候AD导出的线就没有缺失的了:

AI在小分子领域应用

5 小分子应用的AI 在化学中&#xff0c;小分子指的是相对分子量较低的有机化合物。它通常由少量原子组成&#xff0c;通常少于100个&#xff0c;并具有明确定义的化学结构。小分子与大分子相对比&#xff0c;大分子如蛋白质、核酸和聚合物在大小上要大得多&#xff0c;通常具有…

React脚手架-详细解析目录与运行

分析执行流程就是&#xff1a;导库 -> 页面节点 -> 组件 -> 组件挂载页面 这里面核心就是 页面节点index.html 、 组件挂载页面 index.js 、 组件render App.js index.css 是对页面的渲染&#xff08;通用型样式&#xff09; 、App.css 是对组件的渲染 首先就是执…

【51单片机】9-定时器和计数器

1.定时器的介绍 1.什么是定时器 &#xff08;1&#xff09;SoC的一种内部的外设【在单片机里面&#xff0c;但是在CPU外面】 &#xff08;2&#xff09;定时器就是CPU的”闹钟“ 2.什么是计数器 &#xff08;1&#xff09;定时器就是用计数的原始实现的 &#xff08;2&#xf…

PyCharm中使用pyqt5的方法2-2

1.2 是否下载成功 按照以上步骤安装了“pyqt5”、“pyqt5-tools”模块和“pyqt5designer”模块后&#xff0c;可以打开保存这三个模块的路径&#xff0c;找到其对应的文件夹&#xff0c;即可验证是否下载成功。 获取PyCharm保存下载模块路径的方法是&#xff0c;在PyCharm界面…

Blender 之创建一个简单的笔筒

文章目录 成品图实现步骤 你是不是想创建一个笔筒捏&#xff1f; follow me! 成品图 实现步骤 先添加一个柱体 选中柱体&#xff0c;然后按tab 进入编辑模式 切换到面模式 &#xff08;可以按主键盘的 3 键&#xff09; 分别选中上下面&#xff0c;鼠标右键&#xff0c;选…

风力发电一键求助可视对讲终端

SV-11SV 风力发电一键求助可视对讲终端 SIP可视对讲终端SV-11SV是专门针对行业用户需求研发的一款高性价比SIP可视对讲产品&#xff0c;外观精致&#xff0c;功能强大&#xff0c;集智能安防、音/视频对讲和广播功能于一体&#xff0c;性价比高。支持壁挂式安装方式。防护等级满…