c语言数据结构(9)——插入排序、希尔排序

news2024/11/16 3:43:22

欢迎来到博主的专栏——C语言数据结构
博主ID:代码小豪

文章目录

    • 排序
    • 插入排序
    • 希尔排序

排序

现在有N个数据的序列,其对应的序列号为[r1 ,r2 ……rn];将该序列对应的数据[k1 ,k2 ……kn]排成满足递减或递减的序列的操作称为排序

插入排序

玩过斗地主的小伙伴都有过这种经历吧,拿到的牌是一些无序的牌组,这时候很难发现卡牌之间的组合,比如顺子、飞机。如果我们将牌顺好之后,牌与牌之间的关系就变得显而易见了。(顺牌:将扑克牌的点数排成升序或者降序)。

不知道大伙顺牌的方式是不是和我一样,比如一个点数为7的牌在大王的后面,我就将这个7插入与7最接近的两个点数的扑克牌之间。
在这里插入图片描述
这个过程是怎样的呢?首先比较7和大王,7比大王小,向后比较,比较7和J,7比J小,向后比较,最后比较7和5, 7比5大,将7插入到5的后面。

细心观察可以发现,7之间的扑克牌已经升序排列了,这和平时打牌的时候一样,将7插入到5与J之间的前提是不是已经将5与J排好了才能插入?对于人来说,这是一个很简单的操作,因为人脑可以随机应变的将5与J拍好序,但是对于机器来说,它是需要一个固定的操作来完成的。我们需要一个稳定的逻辑来实现这种插入排序。

还是回到扑克牌,现在将这个牌型变得更加无序。
在这里插入图片描述
现在该如何用插入排序将这堆牌排成升序呢?

前面将7进行插入排序的时候,需要让7之间的扑克牌点数处于升序状态,从这里可以提炼出一个信息。

(1)若是想要用插入排序将一组数据排成升序,就要先将这个数据的前边数据排成升序
(2)结束插入排序后,这组数据会构成升序。

假如现在有N个数据,那么这N个数据用插入排序算法的思路就应该如下:

(1)为了让n能使用插入排序,将前n-1个数据排成升序,这样就能让n个数据排成升序
(2)为了让n-1个数据能构成升序,对n-1进行插入排序,这就需要先让前n-2个数据排成升序
……
(N-1)为了让前2个数据排成升序,就需要对第2个数据使用插入排序,此时就不存在前一个数据不符合升序的问题了。第一个数据无论如何都满足升序的要求。

从这里可以推断出,如果从第二个数据开始使用插入排序,一直到第N个数据,那么这堆数据就可以完成排序。

在这里插入图片描述

回到扑克牌,我们需要从第二张牌开始进行插入排序
在这里插入图片描述
7比大王小,继续往前比较,但是此时前面不在有点数了,于是将7放在大王的前面在这里插入图片描述
5比大王小,继续向前比较,5又比7小,将5插入至7的前面。
在这里插入图片描述
j比大王小,继续向前比较,j比7大,插入至7的后面。

在这里插入图片描述
此时就完成了4个扑克牌的排序。

插入排序的代码如下:

void InsertSort(int* a, int n)//a是待排序数组,n是数组的元素个数
{
	int end = 0;
	for (int i = 1; i < n ; i++)
	{
		end = i;//从第2个数据开始插入排序,一直到第n个数,构成排序
		int tmp = a[end];//将进行插入排序的数据进行保存,方便找到位置后进行插入
		while (end > 0)
		{
			if (tmp < a[end - 1])
			{
				a[end] = a[end - 1];//将不符合条件的数据向后移动一位,空出空间。
				end--;//继续往前比较
			}
			else//找到适合的位置就退出循环,此时end位于合适的位置
			{
				break;
			}
		}
		a[end] = tmp;
	}
}

希尔排序

希尔排序是插入排序的改进版本,由Shell提出的一种排序算法。插入排序在某种情况下会变得高效,比如数据本就升序或者接近升序的状态,此时插入排序的时间复杂度接近O(N),而非常规情况下的O(N2)。

希尔排序就是利用了这个特点,如果我们可以在进行插入排序之前,先将无序的数据排列的接近有序,这样子插入排序的效率就会变得更高。

如何将数据变得接近有序呢?希尔排序中采用了一种预排序的方法,通过预排序可以简单的想将数据排列成接近有序的序列。预排序的思路如下:

(1)将整个序列分成多个子序列
(2)将子序列的的数据排成有序

那么问题就在于如何分割子序列了:现在有这么一堆无序数据: { 5,3,4,6,7,9,1,8,2 };我们简单将该序列分成3组{5,3,4},{6,7,9},{1,8,2}。进行预排序后的子序列变成{3,4,5},{6,7,9},{1,2,8},合并子序列后的数据变成{3,4,5,6,7,9,1,2,8},这个序列显然是不符合接近有序这个要求的。

想要序列变成接近有序,就需要让大的数据排在后面,小的数据排在前面,这样子的预排序才是有效的,于是希尔想出的预排序方法如下:
子序列不再是相邻的,而是跳跃的.,让相距某个增量的数据组成子序列。
在这里插入图片描述
将子序列进行排序后的序列为
在这里插入图片描述
可以发现这个序列比预排序之前的序列更加有序。如果再对这个序列进行增量更小的预排序,这个序列将会更加更近有序。

那么如何选择预排序的增量呢?常用的方法有两个:一个是让增量等于前一次预排序的增量的一半,另外则是让增量等于前一次预排序的增量的3分之1再加1。但是无论如何,最后一次预排序的增量必须为1,这样才能对序列进行完全的排序。

前面只提到了预排序却没提到预排序的排序方法是什么,实际上预排序采用的排序算法是插入排序的变种之一。插入排序是比较前一个数据,而希尔排序中的预排序是比较前增量个数据。
在这里插入图片描述
每完成一趟预排序,序列更加接近有序。与此同时逐渐减少预排序的增量,让预排序能让序列更加有序。最后一趟希尔排序增量一定要为1,此时整个序列变得有序。

这里先给出希尔排序的程序,再图解过程

void ShellSort(int* a, int n)//n是数组的元素个数
{
	int gap = n;//增量为gap
	int tmp = 0;
	while (gap > 1)
	{
		gap /= 2;//一趟希尔排序后增量变化,保证最后一趟希尔排序的增量为1.
		//也可以写成,gap=gap/3+1,各有优劣
		for (int i = 0; i < n - gap; i++)//一趟预排序
		{
			int end = i;
			while (end >= 0)
			{
				tmp = a[end + gap];
				if (a[end] > a[end + gap])
				{
					a[end + gap] = a[end];//将预排的子序列进行排序
					end -= gap;
				}
				else
				{
					break;
				}
				a[end + gap] = tmp;//插入合适的数据位置
			}
		}
	}
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
可以发现经过两趟排序之后,序列基本有序
在这里插入图片描述
我们对比一下增量为1的希尔排序和插入排序的代码
插入排序的代码:

for (int i = 1; i < n ; i++)
{
	end = i;//从第2个数据开始插入排序,一直到第n个数,构成排序
	int tmp = a[end];//将进行插入排序的数据进行保存,方便找到位置后进行插入
	while (end > 0)
	{
		if (tmp < a[end - 1])
		{
			a[end] = a[end - 1];//将不符合条件的数据向后移动一位,空出空间。
			end--;//继续往前比较
		}
		else//找到适合的位置就退出循环,此时end位于合适的位置
		{
			break;
		}
	}
	a[end] = tmp;
}

增量为1的希尔排序的代码

for (int i = 0; i < n - gap; i++)//一趟预排序
{
	int end = i;
	while (end >= 0)
	{
		tmp = a[end + gap];
		if (a[end] > a[end + gap])
		{
			a[end + gap] = a[end];//将预排的子序列进行排序
			end -= gap;
		}
		else
		{
			break;
		}
		a[end + gap] = tmp;//插入合适的数据位置
	}
}

将希尔排序的增量(gap)改为1,可以发现与插入排序的代码逻辑无异。

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

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

相关文章

誉天华为认证云计算课程如何

HCIA-Cloud Computing 5.0 课程介绍&#xff1a;掌握华为企业级虚拟化、桌面云部署&#xff0c;具备企业一线部署实施及运维能力 掌握虚拟化技术、网络基础、存储基础等内容&#xff0c;拥有项目实施综合能力 满足企业虚拟化方案转型需求&#xff0c;应对企业日益多样的业务诉求…

京东云0基础搭建帕鲁服务器_4核16G和8核32G幻兽帕鲁专用服务器

使用京东云服务器搭建幻兽帕鲁Palworld游戏联机服务器教程&#xff0c;非常简单&#xff0c;京东云推出幻兽帕鲁镜像系统&#xff0c;镜像直接选择幻兽帕鲁镜像即可一键自动部署&#xff0c;不需要手动操作&#xff0c;真正的新手0基础部署幻兽帕鲁&#xff0c;阿腾云atengyun.…

项目模块—实现抑郁测评(小程序)

script <script setup> import { ref } from "vue";//控制轮播图页码 let current ref(0);//答题逻辑 const add (value) > {if (current.value < 9) {current.value current.value 1;} else {uni.switchTab({url: "/pages/my/my",});} }…

51单片机学习笔记11 使用DS18B20温度传感器

51单片机学习笔记11 使用DS18B20温度传感器 一、DS18B20简介1. 主要特点2. 工作原理3. 引脚说明4. ROM 二、1-wire协议简介1. 总线结构&#xff1a;2. 通信方式&#xff1a;3. 数据传输&#xff1a;4. 设备识别&#xff1a;5. 供电方式&#xff1a;6. 应用场景&#xff1a;7. 优…

Docker部署MinIO对象存储服务

1. 拉取MinIO镜像 # 下载镜像 docker pull minio/minio#查看镜像 docker images2. 创建目录 # 文件存储目录 mkdir -p /opt/minio/data# 配置文件 mkdir -p /opt/minio/config# 日志文件 mkdir -p /opt/minio/logs3. 创建Minio容器并运行 docker run \ -p 9000:9000 \ -p 90…

第4章.精通标准提示,引领ChatGPT精准输出

标准提示 标准提示&#xff0c;是引导ChatGPT输出的一个简单方法&#xff0c;它提供了一个具体的任务让模型完成。 如果你要生成一篇新闻摘要。你只要发送指示词&#xff1a;汇总这篇新闻 : …… 提示公式&#xff1a;生成[任务] 生成新闻文章的摘要&#xff1a; 任务&#x…

数据结构——快速排序的三种方法和非递归实现快速排序

数据结构——快速排序的三种方法和非递归实现快速排序&#xff08;升序&#xff09; 前言快速排序的单趟排序hoare法挖坑法前后指针法 快速排序的实现key基准值的选取快速排序代码快速排序的优化 快速排序&#xff08;非递归&#xff09; 前言 快速排序是Hoare于1962年提出的一…

http和https之间的区别和优势

HTTP&#xff08;超文本传输协议&#xff09;和HTTPS&#xff08;安全超文本传输协议&#xff09;是两种在互联网通信中应用广泛的协议&#xff0c;它们在数据传输、安全性、加密等方面有着明显的区别和优势。下面将详细介绍HTTP和HTTPS之间的区别和各自的优势。 区别和优势 1…

admin端

一、创建项目 1.1 技术栈 1.2 vite 项目初始化 npm init vitelatest vue3-element-admin --template vue-ts 1.3 src 路径别名配置 Vite 配置 配置 vite.config.ts // https://vitejs.dev/config/import { UserConfig, ConfigEnv, loadEnv, defineConfig } from vite im…

2024最新版克魔助手抓包教程(9) - 克魔助手 IOS 数据抓包

引言 在移动应用程序的开发中&#xff0c;了解应用程序的网络通信是至关重要的。数据抓包是一种很好的方法&#xff0c;可以让我们分析应用程序的网络请求和响应&#xff0c;了解应用程序的网络操作情况。克魔助手是一款非常强大的抓包工具&#xff0c;可以帮助我们在 Android …

uniApp使用XR-Frame创建3D场景(7)加入点击交互

上篇文章讲述了如何将XR-Frame作为子组件集成到uniApp中使用 这篇我们讲解如何与场景中的模型交互&#xff08;点击识别&#xff09; 先看源码 <xr-scene render-system"alpha:true" bind:ready"handleReady"><xr-node><xr-mesh id"…

阿里云CentOS7安装ZooKeeper单机模式

前提条件 阿里云CentOS7安装好jdk&#xff0c;可参 hadoop安装 的jdk安装部分 下载 [hadoopnode1 ~]$ cd softinstall [hadoopnode1 softinstall]$ wget https://archive.apache.org/dist/zookeeper/zookeeper-3.7.1/apache-zookeeper-3.7.1-bin.tar.gz 解压 [hadoopnode1 …

Svg Flow Editor 原生svg流程图编辑器(四)

系列文章 Svg Flow Editor 原生svg流程图编辑器&#xff08;一&#xff09; Svg Flow Editor 原生svg流程图编辑器&#xff08;二&#xff09; Svg Flow Editor 原生svg流程图编辑器&#xff08;三&#xff09; Svg Flow Editor 原生svg流程图编辑器&#xff08;四&#xf…

flutter 修改app名字和图标

一、修改名字 在Android中修改应用程序名称&#xff1a; 在AndroidManifest.xml文件中修改应用程序名称&#xff1a; 打开Flutter项目中的android/app/src/main/AndroidManifest.xml文件。找到<application>标签&#xff0c;然后在android:label属性中修改应用程序的名称…

Jenkins拉取github项目相关问题

1.私有仓库问题 1.1如果你的仓库是私有的&#xff0c;21年起github就不支持账号密码的方式拉取代码了 那么就需要在github上面创建一个token (classic) 然后在Jenkins代码设置那里 然后应该就可以顺利打包了。 2.找不到pom&#xff08;多了一层文件夹&#xff09;问题 解…

关系型数据库mysql(8)sql高级语句②

目录 一.子查询——Subquery 语法 环境准备 In——查询已知的值的数据记录 子查询——Insert 子查询——Update 子查询——Delete Not In——表示否定&#xff0c;不在子查询的结果集里 Exists——判断查询结果集是否为空 子查询——别名 ​编辑 二.视图 理论&a…

踩坑uniapp中打包Andiord app,在真机调试时地图以及定位功能可以正常使用,打包成app后失效的问题

首先看到这是uni官网提出的&#xff0c;app上建议使用高德地图。 下面就用高德地图进行配置。 步骤一&#xff1a;登陆高德地图控制台 名称和类型根据自己情况填写选择即可 步骤二&#xff1a; 添加key 步骤三&#xff1a;取到SHA1 进入uniapp开发官网 点击应用名称&#…

如何使用Windows电脑部署Lychee私有图床网站并实现无公网IP远程管理本地图片

&#x1f308;个人主页: Aileen_0v0 &#x1f525;热门专栏: 华为鸿蒙系统学习|计算机网络|数据结构与算法|MySQL| ​&#x1f4ab;个人格言:“没有罗马,那就自己创造罗马~” #mermaid-svg-MSVdVLkQMnY9Y2HW {font-family:"trebuchet ms",verdana,arial,sans-serif;f…

Webpack生成企业站静态页面 - 增强数据处理能力

一些项目因需求不同&#xff0c;如需SEO或小项目&#xff0c;使用angular、react或vue就大材小用了。我们可以通过webpack、gulp这些构建工具&#xff0c;也能快速完成html页面开发&#xff0c;并且也能使用less/sass/styus等样式预编译功能&#xff0c;以及将js、html分模块、…

pyecharts操作三

pyecharts操作三 pyecharts 是一个用于生成Echarts图表的Python库。Echarts是百度开源的一个数据可视化JS库&#xff0c;可以生成一些非常酷炫的图表。 环境安装 pip install pyecharts 检查版本 import pyecharts print(pyecharts.version) 2.0.3 GL关系图 import rando…