[算法]插入排序和希尔排序

news2024/11/25 13:29:48

        这里简单的介绍一下插入排序和希尔排序的算法实现,为简单起见,排序为升序且排序的数组是整形数组。

一、插入排序

(一)、算法思路

        把数组里的第一个元素视为有序的,然后取第二个元素与前面的元素作比较,如果该元素小于第一个元素,则把第一个元素往后移,第二个元素往前移,这样,我们数组前两个元素就变得有序了。接着再取第三个元素,将其与前面的元素作比较,如果该元素小于其前面的元素,则将该元素往前移,将被比较的元素往后移,然后再将该元素与前一个元素作比较,如果当该元素大于其前面的元素,那么当前该元素所在的位置就是其正确的顺序,这个时候,数组有序的序列长度增加了一,其结果就是把一个元素插入到前面的已经有序的序列当中去,所以叫做插入排序,以此重复插入排序,数组变得有序。

下面是插入排序的动图:

(二)、算法的实现 

void InsertSort(int* arr, int nums)
{
	for (int i = 1; i < nums; i++)
	{
		int key = arr[i];//存储待插入排序的值

		int j;
		for (j = i; j > 0; j--)
		{
			//依次往前作比较进行移动
			if (key < arr[j - 1])
				arr[j] = arr[j - 1];
			else
				break;
		}

		//此时j的位置就是key插入排序的位置
		arr[j] = key;
	}
}

(三)、时间复杂度和稳定性

        插入排序的时间复杂度为O(n^{2})当待排序的数组为完全或接近有序时,插入排序的时间复杂度为O(n),而当待排序的数组完全或接近逆序时,插入排序的时间复杂度为O(n^{2})

        插入排序是稳定的。

二、希尔排序

        希尔排序(Shell's Sort)插入排序的一种又称“缩小增量排序”(Diminishing Increment Sort),是直接插入排序算法的一种更高效的改进版本。希尔排序是非稳定排序算法。该方法因 D.L.Shell 于 1959 年提出而得名。

(一)、算法思路

        希尔排序是从插入排序上改进的,先来看看改进了什么。假如有一组数组的序列是逆序的:[10,9,8,7,6,5,4,3,2,1],那么我们的插入排序在每次插入待排序的元素时,都要以一次移动一个数据这样(增量为一)依次移动到数组的开头位置,这样时间复杂度就为O(n)了。而我们的希尔排序一开始以一个增量开始跳跃式的进行插入排序,叫做预排序将数组中较小的元素移动到数组的左边去,将数组中较大的元素移动到数组的右边去,排序一次后,数组左边差不多都是小的元素,数组的右边差不多都是大的元素。再缩小增量进行增量插入排序,跳跃进行插入排序的跳跃元素个数减小,执行该增量的插入排序,以此重复,每次执行完增量插入排序后数组的元素逐渐接近有序,当增量变为一时,执行的是朴素的插入排序,这个时候因为预排序的作用数组的元素已经非常接近有序了,执行完插入排序后,数组变为有序。

下面以缩小增量为除以2进行希尔排序来演示,假设待排序的数组为:

57210643189

增量为5:

以增量为10 / 2 = 5 分组进行增量插入排序
57210643189
对第一组红色元素进行增量插入排序
47210653189
对第二组黄色元素进行增量插入排序
43210657189
对第三组绿色元素进行增量插入排序
43110657289
对第四组蓝色元素进行增量插入排序
43186572109
对第五组紫色元素进行增量插入排序
43186572109

增量为2:

以增量为5 / 2 = 2为增量分组进行插入排序
43186572109
对第一组红色元素进行增量插入排序
13486572109
对第二组黄色元素进行增量插入排序
12436578109

增量为1:

以增量为2 / 2 = 1为增量进行朴素插入排序
12436578109
对第一组红色元素进行增量插入排序
12345678910

        我们可以看到,前两次的预排序使得最后一次的朴素插入排序非常轻松,因为待排序的数组经过预排序后变得十分接近有序了。

(二)、算法实现 

//希尔排序
void SheelSort(int* arr, int nums)
{
	int gap = nums;
	
	while (gap > 1)
	{
		//缩小增量进行插入排序
		gap /= 2;

		//分组进行插入排序
		//有gap组
		for (int i = 0; i < gap; i++)
		{
			//增量为gap的插入排序
			for (int j = i + gap; j < nums; j += gap)
			{
				int key = arr[j]; //存储待增量插入排序的值

				int k;
				//注意这里的结束条件是k >= gap 因为要保证k - gap >= 0
				for (k = j; k >= gap; k -= gap)
				{
					//依次往前作比较进行移动
					if (key < arr[k - gap])
						arr[k] = arr[k - gap];
					else
						break;
				}
				//此时k的位置就是key插入的位置
				arr[k] = key;
			}
		}

	}
}

上面的代码有三个循环嵌套,我们还可以使其变得简单点。

        我们可以在每次进行增量插入排序时,i从0遍历到nums - gap - 1的位置,然后依次将其遍历的位置的以增量为单位的下一个元素key进行增量插入排序

比如上面的:

以增量为5 / 2 = 2为增量分组进行插入排序
43186572109

我们可以这样进行增量插入排序:

i = 0

将key = 1 插入到有序序列 4 中

结果:

 

i = 1

key = 8 插入到有序序列 3 中

结果:

 

 

i = 2

key = 6 插入到有序序列 1 4 中

结果:

i = 3

key = 5 插入到有序序列 3 8 中

结果:

i = 4

key = 7 插入到 有序序列 1 4 6 中

结果不变

 i = 5 

key = 2 插入到有序序列 3 5 8 中

结果:

i = 6

key =10 插入到 有序序列 1 4 6 7 中

结果不变 

i = 7

key = 9 插入到有序序列 2 3 5 8 9 中

结果不变:

12436578109

这就是通过从头遍历实现执行一次预排序的过程。

具体代码如下:

void SheelSort(int* arr, int nums)
{
	int gap = nums;

	while (gap > 1)
	{
		gap /= 2;

		for (int i = 0; i < nums - gap; i++)
		{
			int j;
			int key = arr[i + gap];//存储待插入排序的值
			for (j = i; j >= 0; j -= gap)
			{
				if (key < arr[j])
					arr[j + gap] = arr[j];
				else
					break;
			}
			//此时j + gap的位置为key插入的位置
			arr[j + gap] = key;
		}
	}
}

(三)、时间复杂度和稳定性

        希尔排序的时间复杂度比较复杂,大概为O(n^{1.3-2}),其排序算法不稳定。

        上面的代码中的缩小增量为除以2,其实还可以是其他值,如 3 4 5 .....,只要保证最后一次可以执行增量为1的朴素插入排序即可,如当缩小增量的倍率为3时,gap = gap / 3 + 1。

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

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

相关文章

2024钉钉杯A题思路详解

文章目录 一、问题一1.1 问题1.2 模型1.3 目标1.4 思路1.4.1 样本探究1.4.2 数据集特性探究&#xff1a;1.4.3 数据预处理1.4.4 数据趋势可视化1.4.5 ARIMA和LSTM两种预测模型1.4.6 参数调整 二、问题二2.1 问题2.2 模型2.3 目标2.4 思路2.4.1 样本探究2.4.2 数据集特性探究2.4…

jenkins中shell脚本中使用构建参数化Groovy变量的四种方式

jenkins中shell脚本中使用构建参数化Groovy变量的四种方式: 以字符变量为例&#xff1a; 流水线代码&#xff1a; pipeline {agent {//label "${server}"label "${28}"}stages {stage(Hello) {steps {echo Hello Worldecho "${28}"echo "…

C语言-TCP通信创建流程

TCP通信创建流程 1. 客户端创建TCP连接 在整个流程中, 主要涉及以下⼏个接⼝socket() : 创建套接字, 使⽤的套接字类型为流式套接字connect() : 连接服务器send() : 数据发送recv() : 数据接收创建套接字 首先&#xff0c;我们需要创建套接字&#xff0c;套接字是通信的基础…

Adobe Lightroom Classic 2024(LRC2024)软件下载(附下载链接)+LRC教程

目录 一、简介 二、下载 三、功能 四、使用操作 一、简介 Adobe Lightroom Classic 2024&#xff08;简称LRC2024&#xff09;是Adobe公司推出的一款专业级照片处理和管理软件&#xff0c;广泛应用于摄影师和摄影爱好者中。作为Adobe家族的一员&#xff0c;LRC2024在继承前…

平价不入耳运动耳机哪款最好?五款回购榜优品种草

许多有健身运动习惯的朋友在选择耳机时会优先考虑不入耳耳机&#xff0c;因为它佩戴舒适&#xff0c;稳固性和安全性更高&#xff0c;不仅在运动时不会轻易掉落&#xff0c;还能够方便我们在进行户外运动时接收外界的声音。那么&#xff0c;平价不入耳运动耳机哪款最好&#xf…

Spark实时(一):StructuredStreaming 介绍

文章目录 Structured Streaming 介绍 一、SparkStreaming实时数据处理痛点 1、复杂的编程模式 2、SparkStreaming处理实时数据只支持Processing Time 3、微批处理,延迟高 4、精准消费一次问题 二、StructuredStreaming架构与场景应用 三、​​​​​​​​​​​​​​…

C++·set与map容器(下)

本节把红黑树封装到set与map容器中去主要就是迭代器的自增自减&#xff0c;封装的大部分内容都展示到最后代码中了 1. 红黑树的改造 因为set容器只有关键码值&#xff0c;map容器中不仅要存关键码值&#xff0c;还要存关键码值对应的数据。但是红黑树只有一颗&#xff0c;我们…

Python操作PostgreSQL指南

文本介绍了使用Python中的psycopg2库来操作PostgreSQL数据库&#xff0c;包括安装必要的包、建立和关闭连接、执行增删改查操作以及处理可能的异常。这些操作将在Python应用程序中与PostgreSQL数据库进行有效的交互。 一. 简介和包的安装 PostgreSQL是一个强大、开源的对象关…

技术分享!国产ARM + FPGA的SDIO通信开发介绍!

SDIO总线介绍 SDIO(Secure Digital lnput and Output),即安全数字输入输出接口。SDIO总线协议是由SD协议演化而来,它主要是对SD协议进行了一些扩展。 SDIO总线主要是为SDIO卡提供一个高速的I/O能力,并伴随着较低的功耗。SDIO总线不但支持SDIO卡,而且还兼容SD内存卡。支持…

web前端开发一、VScode环境搭建

1、VScode安装live server插件&#xff0c;写完代码后&#xff0c;保存就会在浏览器自动更新&#xff0c;不需要再去浏览器点击刷新了 2、创建html文件 3、在文件中输入感叹号 &#xff01; 4、选择第一个&#xff0c;然后回车&#xff0c;就会自动输入html的标准程序 5、…

【Linux C | 网络编程】进程池零拷贝传输的实现详解(四)

上一篇解决了进程池中进行大文件传输的问题&#xff0c;通过循环接收和发送指定大小的内容实现大文件的可靠传输。 【Linux C | 网络编程】进程池大文件传输的实现详解&#xff08;三&#xff09; 但是其中不可避免的在循环中使用多次的send和recv&#xff0c;这就涉及到多次…

0725_驱动1 内核中并发和竟态解决方法

一、内核中并发和竟态相关概念 一、什么时候产生竟态 1.同一个驱动程序&#xff0c;同时被多个应用层程序进行访问 2.访问同一个临界资源&#xff0c;驱动产生竟态 二、竟态产生根本原因 1.在单核cpu中&#xff0c;如果内核支持抢占&#xff0c;就会产生竟态 2.在多核cpu中&…

Internxt:适用于Linux开源安全云存储平台

有无数的云存储平台为您的文件提供安全可靠的存储空间。可在 Linux 上安装的热门云存储应用程序包括Dropbox、Nextcloud和Google Drive&#xff0c;遗憾的是&#xff0c;后者迄今为止不提供 Linux 客户端。 其他自托管选项包括OwnCloud、Pydio Cells、Seafile、Resilio和Synct…

【C++深度探索】AVL树与红黑树的原理与特性

&#x1f525; 个人主页&#xff1a;大耳朵土土垚 &#x1f525; 所属专栏&#xff1a;C从入门至进阶 这里将会不定期更新有关C/C的内容&#xff0c;欢迎大家点赞&#xff0c;收藏&#xff0c;评论&#x1f973;&#x1f973;&#x1f389;&#x1f389;&#x1f389; 前言 前…

鱼哥好书分享活动第28期:看完这篇《终端安全运营》终端安全企业基石,为你的终端安全保驾护航!

鱼哥好书分享活动第28期&#xff1a;看完这篇《终端安全运营》终端安全企业基石&#xff0c;为你的终端安全保驾护航&#xff01; 读者对象&#xff1a;主要内容&#xff1a;本书目录&#xff1a;了解更多&#xff1a;赠书抽奖规则: 在当前网络威胁日益复杂化的背景下&#xff…

SGLang 大模型推理框架 qwen2部署使用案例;openai接口调用、requests调用

参考: https://github.com/sgl-project/sglang 纯python写,号称比vllm、tensorRT还快 暂时支持模型 安装 可以pip、源码、docker安装,这里用的pip 注意flashinfer安装最新版,不然会可能出错误ImportError: cannot import name ‘top_k_top_p_sampling_from_probs’ fr…

FreeSWITCH 1.10.10 简单图形化界面27-Auto-Answer功能

FreeSWITCH 1.10.10 简单图形化界面27-Auto-Answer功能 1、前言2、测试环境3、呼叫测试 1、前言 在某些支持 Auto-Answer 消息头的 SIP 设备上&#xff0c;我们可以通过使用 FreeSWITCH 的 sip_auto_answer 变量来实现 SIP 设备的自动接听功能。即使 SIP 设备本身没有明确地启…

【无为则无心SpringBoot】— 1.SpringBoot介绍

1、什么是SpringBoot SpringBoot是Spring家族中的一个全新的框架&#xff0c;它用来简化Spring应用程序的创建和开发过程&#xff0c;也可以说SpringBoot能简化我们之前采用SpringMVCSpringMybatis框架进行开发的过程。 我们在使用Spring Boot时只需要配置相应的Spring Boot配置…

开源数据结构存储系统Redis的内部数据结构详解(上)

目录 1、简单动态字符串 1.1、SDS的定义 1.2、SDS与C字符串的区别 2、链表 2.1、链表的定义 2.2、特性 3、字典 3.1、哈希表定义 3.2、哈希表节点定义 3.3、字典定义 3.4、Rehash 3.5、渐进式rehash 4、总结 C++软件异常排查从入门到精通系列教程(专栏文章列表,…

ReentrantReadWriteLock详解

目录 ReentrantReadWriteLock详解1、ReentrantReadWriteLock简介2、ReentrantReadWriteLock类继承结构和类属性3、ReentrantReadWriteLock的读写锁原理分析4、ReentrantReadWriteLock.WriteLock类的核心方法详解非公平写锁的获取非公平写锁的释放公平写锁的获取公平写锁的释放 …