手撕希尔排序

news2024/11/23 16:57:51

什么是希尔排序?他的效率怎摸样,如何去实现希尔排序呢?在这之前可能我们已经了解了希尔排序,作为排序中的老大哥一员,希尔排序的效率也是屈指可数的。

想要知道希尔排序如何实现我们就的先了解插入排序。

目录

1.何为插入排序

 2.插入排序的实现

3.何为希尔排序

4.希尔排序的实现

5.希尔排序的时间复杂度


1.何为插入排序

插入排序是一种简单直观的排序算法,其基本思想是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。插入排序在实现上,通常采用in-place排序(即只需用到O(1)的额外空间的排序),因而在从后向前扫描过程中,需要反复把已排序元素逐步向后挪位,为最新元素提供插入空间。。

具体实现逻辑如下:

从第一个元素开始,该元素可以认为已经被排序。
取出下一个元素,在已经排序的元素序列中从后向前扫描。如果该元素(已排序)大于新元素,将该元素移到下一位置,重复步骤3,直到找到已排序的元素小于或者等于新元素的位置。将新元插入到该位置后,重复步骤2~5。

 这里我们可将插入排序形象地理解为打牌时我们摸牌插入到手中牌堆的思想,在日常生活中插入排序也遍布在我们的身边。

 2.插入排序的实现

插入排序,从第一个元素开始,将下一个元素tmp与之比较,若大于tmp,则该位置的数据后移一位,此时end--,该位置空出,之后tmp插入到该位置,实现前插。若大于tmp,跳出循环,刚好插到该元素后面的位置。以此往复,实现排序。

插入排序这里的循环条件根据你判断i是小于n还是n-,改变end与tmp对应的位置。

void InsertSort(int* a, int n)
{
	for (int i = 0; i < n-1; ++i)
	{
		// [0, end] 有序,插入tmp依旧有序
		int end = i;
		int tmp = a[i+1];

		while (end >= 0)
		{
			if (a[end] > tmp)
			{
				a[end + 1] = a[end];
				--end;
			}
			else
			{
				break;
			}
		}

		a[end + 1] = tmp;
	}
}

 可以看到插入排序的时间复杂度根源数据的顺序度的有关系的,越顺序时间复杂度越小,最好的情况是O(N),最坏的情况是逆序,先还是一个等差数列的求和,故时间复杂度为O(N^2).

实际上插入排序的时间复杂度是较高的了,相对于冒牌排序两者效果差不多,插入略快一点点。

3.何为希尔排序

在深入了解了插入排序时,一个叫shell的大佬就思考如何将在实现插入排序前时,能否将数据先变得更加有序一些,而不是毫无顺序,这样使得排序的时间复杂度低一些,于是他们提出了一个思想,在进行插入排序时,先将数据分组,每一组中的数据相差gap个,每一组数据进行类似插入排序的思想先进行分组排序,之后进行插入排序,于是大名鼎鼎的希尔排序就此诞生!

例如

我们对于组数逆序的数组(我们是降序排列)a[]={9,8,7,6,5,4,3,2,2,1,0},这样更明显的展示。

预排序:

 现在就是开始排序

我们已经知道排序的代码:

添加循环,于是分组排序代码就如下

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

  当然这里的代码我们可以简化一下利用分组数据,每组齐头并进的思想简化如下:

这两种方式效率都是一样的,只不过代码得到了简化:

for (int i = 0; i < n-gap; i++)
		{
			//每组齐头并进一次插入排序
			int end = i;//第i个位置
			int tmp = arr[end+gap];//第i+gap个位置
			while (end >= 0)
			{
				if (arr[end] > tmp)
				{
					arr[end + gap] = arr[end];
					end -= gap;
				}
				else
				{
					break;
				}
				arr[i + gap] = tmp;
			}

我们发现:      

 

 

 循环最终结果为:

 此时我们发现该组数已经变得逐渐有序,这就是最重要的思想之一,当然我们可以发现该代码与插入排序非常的相似,两者的区别仅仅是因为gap的取值,当gap为1时,便就是希尔排序。

4.希尔排序的实现

明白以上的预排序我们就正式进入希尔排序,所谓希尔排序就是:

1.先进行预排序。

2.gap==1时在进行插入排序。

在预排序中我们了解,当gap越大排序越不是那么有序,组数也较少,当gap越小,排的越为顺序,组数较多,可是时间复杂度高且排序的数过多时gap不能越小。于是希尔排序就决定每一次排序就变换gap的值,动态变换排序。

于是就实现了希尔排序:

void ShellSort(int* a, int n)
{
	// 1、gap > 1 预排序
	// 2、gap == 1 直接插入排序

	int gap = n;
	while (gap > 1)
	{
		gap = gap / 3 + 1;  // +1可以保证最后一次一定是1
		// gap = gap / 2;
		for (int i = 0; i < n - gap; ++i)
		{
			int end = i;
			int tmp = a[end + gap];
			while (end >= 0)
			{
				if (a[end] > tmp)
				{
					a[end + gap] = a[end];
					end -= gap;
				}
				else
				{
					break;
				}
			}

			a[end + gap] = tmp;
		}
	}
}

5.希尔排序的时间复杂度

事实上,希尔排序的时间复杂度很难求解,因为随着gap的变化每一次循环的时间复杂度都是不一样的,它是一种动态变化,想要求解比较困难,但我们不难发现,希尔排序的速度时令人震惊的,

因此Hibbard提出了著名的Hibbard增量:1, 3, 7, ..., 2^K−1 。使用这个增量的希尔排序最坏运行时间是 O(N^3/2) 。

通俗来说,能打破二次时间界的核心原因是:

在执行 hk排序之前,我们已经执行了 ℎk+1,hk+2 排序。而这两个排序使得序列在宏观上更有序,并且严格地保证了对于某个位置的元素E,在这个元素左侧,且到E一定距离以上的元素一定小于E。

总的来说:

希尔排序的时间复杂度是O(n^(1.3-2)),空间复杂度为常数阶O(1) 。希尔排序没有时间复杂度为O(n(logn))的快速排序算法快,因此对中等大小规模表现良好,但对规模非常大的数据排序不是最优选择,总之比一般O(n^2)复杂度的算法快得多 。

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

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

相关文章

Flutter 笔记 | Flutter 核心原理(六)Embedder 启动流程(Android)

Embedder是Flutter接入原生平台的关键&#xff0c;其位于整个Flutter架构的底层&#xff0c;负责Engine的创建、管理与销毁&#xff0c;同时也为Engine提供绘制UI的接口&#xff0c;那么底层的实现细节如何&#xff1f;本文将详细分析。 Embedder关键类分析 在正式分析Embedd…

chatgpt赋能python:Python知识|关联两个列表

Python 知识 | 关联两个列表 Python 是一种高效的编程语言&#xff0c;它能够很好地进行数据处理&#xff0c;因此在 SEO 领域得到广泛的应用。关联两个列表是一种基础的数据处理方法&#xff0c;本文将为读者详细介绍如何使用 Python 关联两个列表&#xff0c;并给出一些实例…

Rust每日一练(Leetday0018) N皇后II、最大子数组和、螺旋矩阵

目录 52. N皇后 II N Queens II &#x1f31f;&#x1f31f;&#x1f31f; 53. 最大子数组和 Maximum Subarray &#x1f31f;&#x1f31f; 54. 螺旋矩阵 Spiral Matrix &#x1f31f;&#x1f31f; &#x1f31f; 每日一练刷题专栏 &#x1f31f; Rust每日一练 专栏…

chatgpt赋能python:Python关键词匹配:优化你的SEO策略

Python关键词匹配&#xff1a;优化你的SEO策略 在当今数字时代&#xff0c;搜索引擎是许多人获取信息和发现新客户的主要渠道。对于企业或个人网站来说&#xff0c;优化SEO&#xff08;搜索引擎优化&#xff09;策略变得至关重要。在SEO的世界里&#xff0c;关键词匹配是一个重…

springboot+vue编程训练考试测试系统设计与实现

本编程训练系统管理员功能有管理员和用户。管理员功能有个人中心&#xff0c;用户管理&#xff0c;题库资源管理&#xff0c;用户交流&#xff0c;试卷管理&#xff0c;留言板管理&#xff0c;试题管理&#xff0c;系统管理&#xff0c;考试管理。用户可以查看题库资源&#xf…

chatgpt赋能python:使用Python进行人民币兑换-带着您深入了解

使用Python进行人民币兑换 - 带着您深入了解 在当今日益全球化的世界里&#xff0c;进行货币兑换已成为很正常的事情。人民币是世界上最常用的货币之一&#xff0c;而Python作为一种强大的编程语言&#xff0c;可以帮助我们进行人民币兑换计算。本文将介绍如何使用Python进行人…

使用CCProxy搭建windows系统阿里云socket代理服务器 教程

目录 1. 通过windows远程连接阿里云服务器2. 云服务器上安装CCProxy2.1 CCProxy下载安装2.2 设置协议、代理服务、端口号和ip2.3 新建代理用户2.4 确保你的CCProxy启动了服务 3. 在阿里云实例安全组中开放代理端口3.1 前往安全组页面3.2 添加你对应服务的开放端口 总结 欢迎关注…

Java键盘事件处理及监听机制解析

文章目录 概念KeyEventKeyListener代码演示总结 概念 Java事件处理采用了委派事件模型。在这个模型中&#xff0c;当事件发生时&#xff0c;产生事件的对象将事件信息传递给事件的监听者进行处理。在Java中&#xff0c;事件源是产生事件的对象&#xff0c;比如窗口、按钮等&am…

java企业级信息系统开发学习笔记11 利用MyBatis实现条件查询

文章目录 一、学习目标1.对学生表进行条件查询&#xff0c;涉及姓名、性别和年龄三个字段。2.比如查询姓“吴”&#xff0c;性别为“女”&#xff0c;同时年龄为19的学生记录 二、打开上一笔记mybatis项目三、对学生表实现条件查询&#xff08;一&#xff09;创建学生映射器配置…

如何使用wget下载(录制)流媒体或直播推流文件,以及下载出现“正在把输出重定向至 “wget-log.1””错误该怎么办

下载推流文件其实非常简单&#xff0c;就是通常使用的最简单的命令&#xff1a; wget URL -O 输出文件名这里最好设置一下输出文件名&#xff0c;不然很可能下载的文件名称会很奇怪&#xff0c;导致格式识别错误或者其他问题。 不过&#xff0c;如果你直接使用这个命令很可能…

微信小程序nodejs+vue图书馆自习室座位管理系统vax51

系统设计需要从用户和管理员的实际需求开始&#xff0c;以了解他们需要实施哪些功能以及他们可以包括哪些管理工作。 考虑到图书馆座位预约系统小程序系统设计的特点&#xff0c;应满足几个要求&#xff1a;开发语言 node.js 框架&#xff1a;Express 前端:Vue.js 数据库&#…

[MySQL从入门到精通]MySQL概述及安装

前言 你是否想过我们在登录各种各样的网站时候&#xff0c;所需要输入的账号密码&#xff0c;它们存储在哪里&#xff1f;你猜对了&#xff0c;就是今天我们所要说的数据库 目录 前言 1.数据库的概述 1.1 数据 1.2 数据库 1.3数据库的种类 1.4数据库管理系统 2.MySQL的…

CSS 水平垂直居中的方式

目录 在不知道子元素宽高的情况下&#xff0c;水平垂直居中的六种方式&#xff1a; 1、弹性盒子布局方式来实现&#xff08;flex&#xff09;。 2、绝对定位 transform 3、table标签 4、display&#xff1a;table-cell 5、display: grid 6、writing-mode 属性 在不知道子…

chatgpt赋能python:10年Python编程经验的工程师推荐:免费的PythonIDE

10年Python编程经验的工程师推荐&#xff1a;免费的Python IDE 作为一名有着10年Python编程经验的工程师&#xff0c;我一直在寻找可以帮助我提高效率的Python IDE。在这个过程中&#xff0c;我试用了许多付费和免费的IDE&#xff0c;最终发现了一些免费的Python IDE&#xff…

chatgpt赋能python:Python关闭程序语句:顺畅退出程序的方式

Python关闭程序语句&#xff1a;顺畅退出程序的方式 当我们创建一个Python程序时&#xff0c;我们需要确保该程序以正确的方式结束&#xff0c;而不是通过强制终止或强制关闭窗口这样的极端行为。 这种情况可能会导致数据丢失和资源泄漏&#xff0c;从而影响程序的稳定性和可靠…

chatgpt赋能python:Python在计量中的应用

Python在计量中的应用 Python是一种高级编程语言&#xff0c;已经成为了计量学中不可缺少的工具。 Python有一个强大的生态系统&#xff0c;包括庞大的第三方库&#xff0c;这些库提供了丰富的机器学习、数据可视化和分析工具&#xff0c;这些工具在计量学中发挥了极为重要的作…

【vue2+docx-preview】实现docx文档预览(自定义修改样式)

前言 使用vue预览docx的解决方案&#xff0c;过去还有一种Mammoth 。 它旨在转换 .docx 文档&#xff08;例如由 Microsoft Word 创建的文档&#xff09;&#xff0c;并将其转换为 HTML。 不支持样式。实现方式可以参考&#xff1a;Vue Word预览之mammoth.js 因此选择换成支持…

【thingsboard+NodeRed+chirpstack】实现Lora节点设备的数据上下行通讯

本文主要实现基于 thingsboard+NodeRed+chirpstack 实现 lora设备的数据上下行通讯。 NodeRed作为mqtt桥接器,在开源的社区版 thingsboard上实现 这里写目录标题 LoRa 设备上下行通讯方案数据上行数据下行Device 层面创建设备时,要添加 relation规则链层面灯控模块规则链规则…

【libtorch】pytorch源码编译生成c++ 17 libtorch记录

文章目录 1. 问题描述2. 编译安装前准备3. 编译安装4. 编译好之后使用 1. 问题描述 ubuntu20.04 ros2 humble使用1.8.0 libtorch出现coredump&#xff0c;提示加载模型失败&#xff1a; 原因&#xff1a; ros2 humble项目使用c17编译&#xff0c;c11的libtorch的库文件版本不配…

基于springboot+Vue的汽车商城销售4s店服务系统

基于Vue构建一个汽车服务商城&#xff0c;邀请各大商家入住平台&#xff0c;主要包括邀请洗车店、邀请汽车配件商店、邀请4s店入住、邀请汽车美容店入住、邀请汽车修理店入住平台等。这个平台为了给商家和用户提供便利&#xff0c;用户可以更方便体验汽车服务&#xff0c;商家可…