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

       各位看官们好,接下来鄙人想与大家分享的实现被称为六大排序之一的插入排序。其实关于这六大排序在我们最开始就已经接触过了。我们在最开始学习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之后就是正式的排列了。  当然希尔排序其实是有一点困难的,大家需要多理解一点多看一下,其实相对还是比较简单的,只需要理解之后大家都能写出来的。

总结     

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

 

 

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

单线程 vs 多进程:Python网络爬虫效率对比

概述 在网络爬虫的开发过程中&#xff0c;性能优化是一个重要的考虑因素。本文将概述单线程和多进程在Python网络爬虫中的应用&#xff0c;并对比它们的效率。 单线程爬虫是最基本的爬虫模型&#xff0c;它按顺序一个接一个地处理任务。这种方法的优点是实现简单&#xff0c;易…

2024最新TikTok抖音国际版,tiktok正版免拔卡安装来了!

保姆级教程&#xff01;2024最新TikTok抖音国际版&#xff0c;无限制&#xff01;tiktok正版免拔卡安装方法来了&#xff01; TikTok这款APP为何让全球都为之疯狂&#xff1f;因为它更懂人性&#xff0c;懂的人都懂&#xff01; 我是你的老朋友阿星&#xff0c;今天阿星要给大…

7777777777777

欢迎关注博主 Mindtechnist 或加入【智能科技社区】一起学习和分享Linux、C、C、Python、Matlab&#xff0c;机器人运动控制、多机器人协作&#xff0c;智能优化算法&#xff0c;贝叶斯滤波与Kalman估计、多传感器信息融合&#xff0c;机器学习&#xff0c;人工智能&#xff0c…

LeetCode---栈与队列

232. 用栈实现队列 请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作&#xff08;push、pop、peek、empty&#xff09;&#xff1a; 实现 MyQueue 类&#xff1a; void push(int x) 将元素 x 推到队列的末尾int pop() 从队列的开头移除并返回元素int pee…

揭秘SQL中的公用表表达式:数据查询的新宠儿

欢迎来到我的博客&#xff0c;代码的世界里&#xff0c;每一行都是一个故事 揭秘SQL中的公用表表达式&#xff1a;数据查询的新宠儿 前言公用表表述的概述非递归CTE的作用递归CTE的作用CTE性能优化 前言 你是否曾经为SQL查询的复杂性而困扰不已&#xff1f;尤其是那些读写层子…

leetCode.84. 柱状图中最大的矩形

leetCode.84. 柱状图中最大的矩形 题目思路 代码 class Solution { public:int largestRectangleArea( vector<int>& h ) {int n h.size();vector<int> left( n ), right( n );stack<int> st;// 求每个矩形的第一个小于左边界的矩形 - 用单调栈for ( …

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

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

深入解读Meta分析:原理、公式、操作步骤及结果分析;R语言Meta回归分析、诊断分析、不确定性分析与精美作图

目录 专题一 Meta分析的选题与文献计量分析CiteSpace应用 专题二 Meta分析与R语言数据清洗及相关应用 专题三 R语言Meta分析与精美作图 专题四 R语言Meta回归分析 专题五 R语言Meta诊断分析与进阶 专题六 R语言Meta分析的不确定性及贝叶斯应用 专题七 深度拓展机器学习在…

HNU-计算机体系结构-实验1-RISC-V流水线

计算机体系结构 实验1 计科210X 甘晴void 202108010XXX 1 实验目的 参考提供为了更好的理解RISC-V&#xff0c;通过学习RV32I Core的设计图&#xff0c;理解每条指令的数据流和控制信号&#xff0c;为之后指令流水线及乱序发射实验打下基础。 参考资料&#xff1a; RISC-…

图形学初识--矩阵和向量

文章目录 前言正文向量什么是向量&#xff1f;向量涉及哪些常见计算&#xff1f;1、取模2、归一化3、向量加法4、向量减法5、向量与标量乘6、向量点乘&#xff08;内积&#xff09;7、向量投影 向量有哪些基本应用&#xff1f; 矩阵什么是矩阵&#xff1f;矩阵涉及哪些常见计算…

PyTorch张量索引用法速查

作为数据科学家或软件工程师&#xff0c;你可能经常处理大型数据集和复杂的数学运算&#xff0c;这些运算需要高效且可扩展的计算。PyTorch 是一个流行的开源机器学习库&#xff0c;它通过 GPU 加速提供快速灵活的张量计算。在本文中&#xff0c;我们将深入研究 PyTorch 张量索…

Ant Design 动态增减form表单,第二三项根据第一项选中内容动态展示内容

效果图&#xff1a; 选中第一项下拉框&#xff0c;第二第三项展示 点击添加条件&#xff0c;第二条仍然只展示第一项select框 后端返回数据格式&#xff1a; ruleList:[{name:通话时长,key:TALK_TIME,type&#xff1a;’INT‘,unitName:秒,operaObj:[{name:>,value:>…

【旋转链表】python

目录 题目&#xff1a; 思路&#xff1a; 代码&#xff1a; 题目&#xff1a; 思路&#xff1a; 求链表长度&#xff1b;找出倒数第 k1 个节点&#xff1b; 3.链表重整&#xff1a;将链表的倒数第 k1 个节点和倒数第 k个节点断开&#xff0c;并把后半部分拼接到链表的头部。…

基于STM32实现智能交通灯控制系统

目录 引言环境准备智能交通灯控制系统基础代码示例&#xff1a;实现智能交通灯控制系统 GPIO控制交通灯定时器配置与使用红外传感器检测车辆用户界面与显示应用场景&#xff1a;城市交通管理与自动化控制问题解决方案与优化收尾与总结 1. 引言 本教程将详细介绍如何在STM32嵌…

python-合并排列数组 I

问题描述&#xff1a;合并两个按升序排列的整数数组a和b&#xff0c;形成一个新数组&#xff0c;新数组也要按升序排列。 问题示例&#xff1a;输入A[1],B[1],输出[1,1],返回合并后的数组。输入A[1,2,3,4],B[2,4,5,6],输出[1,2,2,3,4,4,5,6],返回合并所有元素后的数组。 完整代…

武汉城投城更公司与竹云科技签署战略协议,携手构建智慧城市新未来!

2024年5月16日&#xff0c;武汉城投城更公司与深圳竹云科技股份有限公司&#xff08;以下简称“竹云”&#xff09;签订战略合作协议&#xff0c;双方将深入推进产业项目合作。 签约现场&#xff0c;双方围绕产业项目合作方向、路径和内容等进行了全面深入交流。城投城更公司党…

JAVA学习路线图

计算机网课资料分享群&#xff1a;710895979

SQL注入攻击是什么?如何预防?

一、SQL注入攻击是什么&#xff1f; SQL注入攻击是一种利用Web应用程序中的安全漏洞&#xff0c;将恶意的SQL代码插入到数据库查询中的攻击方式。攻击者通过在Web应用程序的输入字段中插入恶意的SQL代码&#xff0c;然后在后台的数据库服务器上解析执行这些代码&#xff0c;从而…

AI绘画Stable Diffusion XL 可商用模型!写实艺术时尚摄影级真实感大模型推荐(附模型下载)

大家好&#xff0c;我是设计师阿威 大家在使用AI绘画的时候&#xff0c;是不是遇到这种问题&#xff1a;收藏的模型确实很多&#xff0c;可商用的没几个&#xff0c;而今天阿威将给大家带来的这款写实艺术时尚摄影级真实感大模型-墨幽人造人XL&#xff0c; 对于个人来讲完全是…

P9 【力扣+知识点】【算法】【二分查找】C++版

【704】二分查找&#xff08;模板题&#xff09;看到复杂度logN&#xff0c;得想到二分 给定一个 n 个元素有序的&#xff08;升序&#xff09;整型数组 nums 和一个目标值 target &#xff0c;写一个函数搜索 nums 中的 target&#xff0c;如果目标值存在返回下标&#xff0…