排序进阶----插入排序,希尔排序

       各位看官们好,接下来鄙人想与大家分享的实现被称为六大排序之一的插入排序。其实关于这六大排序在我们最开始就已经接触过了。我们在最开始学习c语言的时候,我们要学习到其中之一的冒泡排序。虽然现在看起来冒泡排序确实是没有太大的实际效果,但是对于我们入门却还是有很大的帮助的。而我们下来介绍的插入排序这是比排序好很多的一个优质排序方法。那废话少说,们来看看插入排排序是如何实现的,并且在实现插入排序后,再看看比插入排序额还厉害的希尔排序

6c0ce7e7f5d14bab9539ea8a07f94f99.jpeg

插入排序思路 

        对于插入排序的话其实还算是比较好理解的。我想大家应该都玩过扑克牌吧。斗地主大家都知道,我们平常的习惯都是按大小排序。这个其实就是插入排序。大家可以想一下,我们如果以扑克牌为例,我们利用冒泡排序的话,每一个位置就要对比一下,这很麻烦,很耗时间的。但是如果我用插入排序的话,我们以第一个数为例,一次向后对比,如果他比接下来对比的数都大的话,那么我就先把战船一直比较比他更大的数,那么我就把它插入在前面。意思就是相当我们暂时把整个数组看着是有序的。那这个数一直对比,一直到遇到比他大的我在插入。在没遇见之前,我就一直想把它存起来。如果都他是最大的话,那么遇到最后一个循环,那么就结束。

      我想我这么说可能是比较难以理解的,大家可以看一下下面这张动图来理解一下。

afae4b37f7034ff18b12ca93ac553ca4.gif

         这样大家可能会理解起来比较简单一些。而且如果大家对数据机构有一点了解的话,就知道插入排序的时间复杂度最坏也才 O(n^2)。那么接下来我们就来尝试一下如何把插入排序写出来。

插入排序实现

         那么我们想想如何实现插入排序呢?我们先从第一趟开始,比如说我们就先走第一趟,以下标为零开始的与下标为一对比,如果他比第一个大的话,那么这一趟就结束,我们就只循环一次。下一次循环我们就循环两次,以下交换后的下标再次循环。如果比前面的数小的话,那么就结束循环。

void InsertSort(int* arr, int n)
{
		int end = 0;
		//待插入的元素
		int tem = arr[end + 1];
		//单趟排
		while (end >= 0)
		{
			//比插入的数大就向后移
			if (tem < arr[end])
			{
				arr[end + 1] = arr[end];
				end--;
			}
			//比插入的数小,跳出循环
			else
			{
				break;
			}
		}
		arr[end + 1] = tem;
}

        这就是插入排序的单次排序。那么我们肯定不是循环一次就能将整个数组变为有序的。那么我就要多循环几次。我们可以看到我们代码最开始是以end开始的。我们把and设为0,那么它就是下标为0与下标为一对比,如果不能将它设为1,那么它就是与下面为1和下面为2对比。那我们就可以再写一个循环,将单次循环放进这个循环里面,End随循环次数增加,但是总体次数要小于我们传入的n小于1。因为我们自己设的要对比的下一个数就是end加一。如果我们这样最开始就是因为小于的话,那么会突出一个随机值。那么这样我们代码就是有问题了。 

void InsertSort(int* arr, int n)
{
	for (int i = 0; i < n - 1; ++i)
	{
		//记录有序序列最后一个元素的下标
		int end = i;
		//待插入的元素
		int tem = arr[end + 1];
		//单趟排
		while (end >= 0)
		{
			//比插入的数大就向后移
			if (tem < arr[end])
			{
				arr[end + 1] = arr[end];
				end--;
			}
			//比插入的数小,跳出循环
			else
			{
				break;
			}
		}
		//tem放到比插入的数小的数的后面
		arr[end + 1] = tem;//为什么写在外面,这是因为防止我们后面有一个最小的数,如果写在里面的话,那么end会减到-1.那么就跳出循环了,无法交换。所以写在外面是防止这样的情况
		//代码执行到此位置有两种情况:
		//1.待插入元素找到应插入位置(break跳出循环到此)
		//2.待插入元素比当前有序序列中的所有元素都小(while循环结束后到此)
	}
}

7c07b8b4340540818b56acd4878f8ba6.png

        这是我设的一个插入排序的一个示例。当然这些里面的势力还算比较简单的,还不足以体现插入排序的优势。但是大家知道冒泡排序是我们六大排序中速度最慢的。我们学会了插入排序,后面如果对希尔排序,如果不了解的话,插入排序也算是一个较好的排序方法。 

      补充:我想大家可能会对代码中的有一个有疑问,就是为什么插入的数大于的话后移,后要end减减嘞。这个是因为我们排序就是下标为1的与下标为0的对比然后交换。是从后向前交换,与冒泡排序的从前往后交换。所以我们第一次是只交换一次。并且大家需要注意的是我在上面还的代码中的,为什么将arr[end + 1] = tem;写在外面。

希尔排序思路

        对于希尔排序来说啊,这其实超过了我们普通人或一般学霸的认知了。其实虽然我们有想可能会想过对一些很混乱的数组我们先给他排简单排一下,然后再进行排序。但是我们简单排序,怎么给他简单排序了?而且反正都要排序的。那不是浪费更多的时间吗?反正这是我个人是这么想的。他也正是因为我们都能想到可以给它初排序一下。但是我们初排序是如何排的呢?我们却并没有想过。但是希尔他就想过了。他想将一个数组用gap(一个数)来个开。就好比是下面这个样子。df89755290ad478c8f849e17f731272b.png

        然后我们以两个节点来对比进行交换。而且我们再将移动到下一个下标。并且也以gap隔离来进行节点交换,这样就完成了我们的初排序。大家可以想象这样是不是就形成了一个相对比较有序的数组?ed9afe30a0c74883976110e39593c2b1.png

        但是大家也知道,我们这个开始想的也就是初排序。我们还需要一个实际排序呀。那么就要用我们上面写的插入排序了。我们插入排序是与下一个进行对比,那我们希尔排序中间隔了gap后再进行对比交换的。那么不知道大家是否要联想到希尔排序与插入排序为基础来实现写的? 

        好了,我们初入排序写了,那么我们接下来该怎么操作呢?我们每一次单趟的gap是确定的。那么如果我们这样第二堂的gap设为第一堂gap的3分之一。那么我们是不是就会比较细一点了?但是我们想想是不是有时候有些时候被3初了会为零,不会为1。那么我们就没有再具体走一遍,是吧?所以我们在除以下之后再加一,那么我们是不是就能保证最后一次为1了。这样我们是不是就最后将整个排序实现了。

14637ac288f0449e9f239d7a77da2e78.gif

希儿排序实现 

       那么上面我们居然写了大概思路。我们还是想插入排序一样,先写单趟如何实现。

void ShellSort(int* arr, int size)
{
	    int gap = 3;
		int i = 0;
		for (i = 0; i < size - gap; i++)	//从0遍历到size-gap-1
		{//为什么是小于size-gap。因为当我们size本来就大于数组个数一个,减去gap后的数就是临界点了,再加一个gap的话就超界了。大家可以想想。
			int end = i;//是不是就是插入排序啊
			int temp = arr[end + gap];
			while (end >= 0)
			{
				if (arr[end] > temp)
				{
					arr[end + gap] = arr[end];
					end -= gap;
				}
				else
				{
					break;
				}
			}
			arr[end + gap] = temp;	//以 end+gap 作为插入位置
		}
}

       不知道大家看到这个是我觉得很熟悉啊,是不是?像我们上面写的插入排序?就是将插入排序中的一改为了gap。是不是就实现了我们说的gap节点,然后进行对比交换了。 那么我们实现了单次排序之后,我们下一次排序。我们在上面说过gap是会变的。一直到为1就成为最后的插入排序,这个大家了解吧。那么就简单了,我们只需要再写一个循环,在循环的时候这样每一次gap进去之后进行改变。

void xixi(int* arr, int size)
{
	int gap = size;
	while (gap > 1)
	{
		gap = gap / 3 + 1;//没进行一次gap后,gap进行改变
        int i = 0;
		for ( i = 0; i < size - gap; i++)
		{
			int end = i;
			int tmp = arr[end + gap];
			while (end >= 0)
			{
				if (arr[end]>tmp)
				{
					arr[end + gap] = arr[end];
					end-=gap;
				}
				else
				{
					break;
				}
			}
			arr[end + gap] = tmp;
		}
	}
}

        这样大家应该能了解了吧。希尔排序简单一点,也就是说我们先以gap为跨点进行一次大的排序,然后再依次减少,依次减少。这样原本乱序的数组就成为了相对有序的数组。最后我们就直接用插入排序,那样是不是就解决了这个问题了?

         所以大家只需要理解,我们先出了gap为1以前的都叫预处理。为1之后就是正式的排列了。  当然希尔排序其实是有一点困难的,大家需要多理解一点多看一下,其实相对还是比较简单的,只需要理解之后大家都能写出来的。

总结     

        好了,以上就是本篇博客想与大家分享的两个排序方法的。大家可以先着重了解插入排序,因为希尔排序是以插入排序为基础而推进发展的。当然如果大家对希尔还是不太了解的话,插入排序现在对目前来说还是很有用的,先了解他的话也是足够了的。好了,本篇博客肯定还有很多不足的地方,希望大家能在评论区留言,方便鄙人来更改。

 

 

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

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

相关文章

【第一节】从C语言到C++

目录 一、面向对象编程 1.早期概念 2.发展与普及 3. 现代发展 二、从C语言到C 1.关于堆内存的使用 2.关于函数重载 3.关于默认参数 4.引用 5.引用参数 6.作用域符号 三、C的输入输出机制 一、面向对象编程 面向对象编程&#xff08;Object-Oriented Programming&am…

Midjourney进阶必看 | 垫图效果的必备技能

还在纠结Midjourney垫图效果不佳&#xff1f;快看看是不是这5点没有做好&#xff01; 前言一、内容形式要一致二、用文本描述强调画面内容三、尝试不同的--iw参数四、用--no参数去除隐藏干扰项五、记得多生成几次 总结 前言 图像提示词&#xff0c;也就是垫图&#xff0c;是Mi…

Verilog实战学习到RiscV - 1 : Yosys 综合

Yosys 综合 实例 一般 FPGA IDE 的第一步都是RTL 综合&#xff08;Synthesis&#xff09;。之后就能看到数字电路图了。然后可以做RTL 级的仿真模拟。 直接上代码&#xff0c;这里我们看一个简单的加法器来学习。 module adder(input [7:0] a,input [7:0] b, input …

Java | Leetcode Java题解之第103题二叉树的锯齿形层序遍历

题目&#xff1a; 题解&#xff1a; class Solution {public List<List<Integer>> zigzagLevelOrder(TreeNode root) {List<List<Integer>> ans new LinkedList<List<Integer>>();if (root null) {return ans;}Queue<TreeNode> n…

el-tabs中的下拉框被覆盖解决方法

解决方法&#xff1a; ::v-deep .el-tabs__content{// overflow:hidden 会导致 分页下拉框超出部分会被.el-tabs__content隐藏overflow: visible; }

基础—SQL—DML(数据操作语言)修改和删除

一、引言 接着上次博客&#xff0c;这次讲解DML语句中的修改数据和删除数据操作。 二、DML—修改数据 UPDATE 表名 SET 字段名1值1 ,字段名2值2 , ...[ WHERE 条件]; 注意&#xff1a;修改语句的条件可以有&#xff0c;也可以没有。如果没有条件&#xff0c;则会修改整张表的…

MySQL 解决登录报错 - 错误1130- Host xxx is not allowed to connect to this server

1、原因 没有给远程连接权限 2、解决 2.1 打开命令行提示符界面输入命令cd C:\Program Files\MySQL\MySQL Server 8.0\bin\ 2.2 连接 MySQL 数据库 输入命令 mysql -u root -p &#xff0c;然后输入密码 回车登录 2.3 查看当前表中的数据库 show databases;查看当前使用的数…

每天写两道(二)LRU缓存、数组中最大的第k个元素

146.LRU 缓存 . - 力扣&#xff08;LeetCode&#xff09; 请你设计并实现一个满足 LRU (最近最少使用) 缓存 约束的数据结构。 实现 LRUCache 类&#xff1a; LRUCache(int capacity) 以 正整数 作为容量 capacity 初始化 LRU 缓存int get(int key) 如果关键字 key 存在于缓存…

在Anki中按某个字段满足的条件查找笔记

Anki中可以使用deck、tag、card、note、is、prop、added、rated、nid、cid等关键字按照牌组、标签、卡片、卡片类型、状态、属性、添加时间、回答时间、对象id等对卡片进行筛选&#xff0c;但是没有提供按卡片字段进行筛选的关键字&#xff0c;那么&#xff0c;怎么按卡片字段是…

C++ (week5):Linux系统编程3:线程

文章目录 三、线程1.线程的基本概念①线程相关概念②我的理解 2.线程的基本操作 (API)(1)获取线程的标识&#xff1a;pthread_self(2)创建线程&#xff1a;pthread_create()(3)终止线程①pthread_exit()&#xff1a;当前线程终止&#xff0c;子线程主动退出②pthread_cancel()&…

安卓ADB通过WIFI无线连接手机[通过无线安装APK]

安卓ADB通过无线连接手机 本文摘录于&#xff1a;https://www.cnblogs.com/zhuxibo/p/14261117.html只是做学习备份之用&#xff0c;绝无抄袭之意&#xff0c;有疑惑请联系本人&#xff01; 别人给的操作确实可行,我这里实操记录如下: AdministratorpiaoranPC MINGW64 /e/Wor…

大模型部署框架 FastLLM 简要解析

0x0. 前言 本文主要是对FastLLM做了一个简要介绍&#xff0c;展示了一下FastLLM的部署效果。然后以chatglm-6b为例&#xff0c;对FastLLM模型导出的流程进行了解析&#xff0c;接着解析了chatglm-6b模型部分的核心实现。最后还对FastLLM涉及到的优化技巧进行了简单的介绍。 0…

Java 阻塞队列与生产者消费者模型

一、阻塞队列 阻塞队列是⼀种特殊的队列&#xff0c;其也遵守队列 "先进先出" 的原则&#xff1b; 阻塞队列是⼀种线程安全的数据结构&#xff0c;并且具有以下特性&#xff1a; 当队列满的时候&#xff0c;继续入队列就会阻塞&#xff0c;直到有其他线程从队列中…

成都市酷客焕学新媒体科技有限公司:助力品牌打破困境!

在数字化浪潮的推动下&#xff0c;营销策略对品牌的发展愈发关键。成都市酷客焕学新媒体科技有限公司&#xff0c;作为短视频营销领域的佼佼者&#xff0c;凭借其卓越的策略和实力&#xff0c;助力众多品牌在信息海洋中脱颖而出&#xff0c;实现品牌的显著增长。 酷客焕学专注于…

抖音和快手哪个好?来全面了解一下他们的区别!

快手和抖音虽然是短视频领域的两大主流平台&#xff0c;但是两者也存在本质的区别&#xff0c;从产品定位、用户群体到视频风格、变现模式&#xff0c;它们的特征都不一样。 &#xff08;一&#xff09;两个平台核心区别&#xff1a; 1. 核心用户不一样&#xff1a;抖音以1、…

【最优化方法】实验四 约束最优化方法的MATLAB实现

实验的目的和要求&#xff1a;通过本次实验使学生较为熟练使用MATLAB软件&#xff0c;并能利用该软件进行约束最优化方法的计算。 实验内容&#xff1a; &#xff11;、罚函数法的MATLAB实现 &#xff12;、可行方向法的MATLAB实现 学习建议&#xff1a; 本次实验就是要通…

942. 增减字符串匹配 - 力扣

1. 题目 由范围 [0,n] 内所有整数组成的 n 1 个整数的排列序列可以表示为长度为 n 的字符串 s &#xff0c;其中: 如果 perm[i] < perm[i 1] &#xff0c;那么 s[i] I 如果 perm[i] > perm[i 1] &#xff0c;那么 s[i] D 给定一个字符串 s &#xff0c;重构排列 pe…

新能源汽车推行精益生产:绿色动力下的效率革命

在新能源汽车行业迅猛发展的当下&#xff0c;推行精益生产已成为提升竞争力的关键所在。精益生产&#xff0c;作为一种以客户需求为导向、追求流程最优化和浪费最小化的管理理念&#xff0c;正逐步在新能源汽车领域展现出其独特的魅力。 新能源汽车的兴起&#xff0c;不仅代表了…

【云原生】kubernetes中Configmap原理解析与应用实战

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者简介&#xff1a;景天科技苑 &#x1f3c6;《头衔》&#xff1a;大厂架构师&#xff0c;华为云开发者社区专家博主&#xff0c;…

Python中tkinter入门编程9

在《Python中tkinter编程入门8-CSDN博客》中提到&#xff0c;tkinter中的Canvas表示画布&#xff0c;可以在画布中显示文字和图片。除了以上功能外&#xff0c;还可以在Canvas中添加对鼠标或键盘的响应。 1 为Canvas添加事件响应 可以通过Canvas的bind()方法添加对鼠标或键盘…