【数据结构与算法】选择排序篇----详解直接插入排序和哈希排序【图文讲解】

 欢迎来到CILMY23的博客

🏆本篇主题为:【数据结构与算法】选择排序篇----详解直接插入排序和哈希排序

🏆个人主页:CILMY23-CSDN博客

🏆系列专栏:Python | C++ | C语言 | 数据结构与算法 | 贪心算法 | Linux | 算法专题 | 代码训练营

🏆感谢观看,支持的可以给个一键三连,点赞关注+收藏。


 前言

本期要讲解的是常见排序算法中的插入排序,插入排序又分两种,一种是直接插入排序,一种是希尔排序。


一、直接插入排序

1.1 插入排序的基本思想:

插入排序是一种简单的插入排序方法,其基本思想是:

把待排序的记录按其关键码值的大小逐个插入到一个已经排好序的有序序列中,直到所有的记录插入完为止,得到一个新的有序序列。

实际中我们玩扑克牌时,就用了插入排序的思想,我们从桌面抽一张牌,然后把牌按照我们所想的情况排序,插入到合适的位置,这就是插入排序的大致过程。

 

1.2 直接插入排序操作:

当插入第i(i>=1)个元素时,前面的array[0],array[1],…,array[i-1]已经排好序,此时用array[i]的排序码与 array[i-1],array[i-2],…的排序码顺序进行比较,找到插入位置即将array[i]插入,原来位置上的元素顺序后移 

 

1.3 直接插入排序的特性总结:

  1. 元素集合越接近有序,直接插入排序算法的时间效率越高
  2. 时间复杂度:O(N^2)(逆序),最好情况是O(N) (顺序有序)
  3. 空间复杂度:O(1),它是一种稳定的排序算法
  4. 稳定性:稳定

1.4 代码实现 

第一部分:

先写单趟的排序,现在取 end 之前的位置都是有序的,要比对的数值是 end+1 的位置数,这里我们用一个变量 tmp 来存储。

我们想实现升序的tmp

如果 tmp 比 end 位置的值小,那么就要把 end 位置的数值往后移动,end 往前移动,直到我们找到 tmp 比 end 位置的数值小,我们就可以直接插入。 

特殊情况:

当 end+1 处的位置为最小值时,此时 end 为 -1 ,tmp 也就是 end+1 的位置处于 0 。

代码:

首先先不管end 是多少,我们知道[0,end]是有序,那end + 1 位置就是我们要比较的数,假设这个数比end位置小,那前面的位置就往后移动,直到数组尽头,或者找到比 end位置要大的数,在这个数的后面进行插入。 

int end;
int tmp = a[end+1];
while(tmp < a[end])
{a[end+1] = a[end];end--;
}
a[end+1] = tmp

为什么最后是end+1?

 取第二种极端情况,也就是插入排序的end走到尽头了,此时end 为 -1 这时候我们要在数组下标0的位置插入,所以要+1。

第二部分

确认多趟的情况 ,首先得保证前 end 都是有序的,想要确认end前有序,我们就再套一层循环,从0开始,让 end 从 0 的位置开始,遍历每个数值过去,这样整个数组都可以实现排序了。

void Insert_Sort(int* a, int n)
{for (int i = 0; i < n - 1; i++){int end = i;int tmp = a[end + 1];while (end >= 0){if (tmp < a[end]){a[end + 1] = a[end];end--;}else{break;}}a[end + 1] = tmp;}
}

 1.5 动图理解

二、希尔排序(缩小增量排序)

2.1 基本思想

希尔排序法又称缩小增量法。

希尔排序法的基本思想是:

先选定一个整数,把待排序文件中所有记录分成按距离的个组,所有距离为gap的记录分在同一组内,并对每一组内的记录进行排序。然后,取,重复上述分组和排序的工作。当到达gap=1时,所有记录在统一组内排好序。

例如下图: 

第一趟排序,gap = 5,从第一个数开始,每隔五个数取一组,9和4为一组;1和8为一组;2和6为一组;5和3为一组,7和5为一组,这样整个数组都分好了,然后在每个小组里面进行排序,9和4排序,因为9比4大,所以9在后面,4在前面,以此类推……

第二趟排序,gap = 3,从第一个数开始,每隔三个数取一组,4,2,5,8,5为一组;1,3,9,6,7为一组;这样整个数组就又分好了,然后在每个小组里面进行排序,4,2,5,8,5排序,排好后,就是4,2,5,8,5.同样以此类推排第二个小组。

在这样的排序下就逐渐接近了有序的数组。我们把这样的操作叫做预排序

最后第三趟排序,当gap == 1时,你会发现,这个跟直接插入排序没有区别,开始取第一个数,保证第一个数有序,然后开始走直接插入的思想。 

通过这样的过程我们就可以发现,直接插入排序也是希尔排序中的一步骤。 

2.2 希尔排序的特性总结:

1. 希尔排序是对直接插入排序的优化。
2. 当gap > 1时都是预排序,目的是让数组更接近于有序。当gap == 1时,数组已经接近有序的了,这样排序起来就会很快。对整体而言,可以达到优化的效果。
3. 希尔排序的时间复杂度不好计算,因为gap的取值方法很多,导致很难去计算,因此在好些树中给出的希尔排序的时间复杂度都不固定,但也有大致算出来的。估计结果为O(n^1.3)

4. 稳定性:不稳定

2.3 希尔排序代码

void Shell_Sort(int *a,int n)
{int gap = n;while (gap > 1){gap = gap / 2;for (int i = 0; i < n - gap; i++){int end = i;int tmp = a[end + gap];while (end >= 0){if (tmp < a[end]){a[end + gap] = a[end];end -= gap;}else{tmp;}}a[end] = tmp;}}
}

2.4 希尔排序操作详解

 希尔排序分两步走,一步是预排序,它的目的是让整个数组接近有序,第二步是直接插入排序

第一种预排序(一组一组排序):

预排序的思路如下:

  1. 先把数组分成以gap为距离的各个小组
  2. 把分好的各单位小组进行插入排序
  3. 对每个小组进行插入排序
第一步:

假设我们现在有这样的三个小组,分别用红,橙,绿三种颜色进行标记。 

把红色的第一个小组单独拿出来

我们标上下标,我们发现对这一个小组进行插入排序,原先的end+1就变成了end+gap。 

现在是交换红色的部分,橙色和绿色我们并不在乎。,因为tmp < nums[end],所以只需要比较end处和end+gap处的值,然后继续直接插入排序的操作即可。

 我们可以仿照直接插入排序写出如下的红色单区排序。

int gap = 3;
int end = 0;
int tmp = a[end + gap];
while (end >= 0)
{if (tmp < a[end]){a[end + gap] = a[end];end -= gap;}else{tmp;}
}
a[end] = tmp;
第二步: 

 然后控制多个红色小组

 我们套一层for循环,注意,j不能超过n-gap,防止end+gap越界。

最大的地方是:end+gap = n - 1

所以 j == end <= n-gap-1 == j < n - gap。

int gap = 3;
for (int j = 0; j < n - gap; j += gap)
{int end = 0;int tmp = a[end + gap];while (end >= 0){if (tmp < a[end]){a[end + gap] = a[end];end -= gap;}else{tmp;}}a[end] = tmp;
}
第三步:

控制多个组进行插入排序 

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

 第二种预排序(多组并排):

 其实这里的多组并排原理很简单,就是让end按照顺序走下去:

也就是将第二步和第三步合并了,这就很接近我们刚开始的步骤。

所以预排序:

gap越大,大的值更快调整到后面,小的值更快调用到前面, 越不接近有序

gap越小, 跳的越慢 越接近有序,如果gap==1,那就是插入排序。

代码:

end每次只走一步,这样一组组的跳,就是多组并排了。 

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

第二步 直接插入排序

要想最后接近有序,每次gap就要变化,最后一次gap==1,所以gap要跟着n进行变化

 所以在外围添加一个循环,当gap > 1的时候是预排序,当gap == 1的时候是直接插入排序。

int gap = n;
while (gap > 1)
{gap = gap / 2;//觉得一次2太小//gap = gap / 3 + 1//...	
}

2.5 希尔排序动图

 


🛎️感谢各位同伴的支持,本期数据结构与算法---选择排序篇就讲解到这啦,如果你觉得写的不错的话,可以给个一键三连,点赞,关注+收藏,若有不足,欢迎各位在评论区讨论。    

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

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

相关文章

Chrome浏览器的Profile数据内容简介

前文简介了Chrome存储的账密/Cookie数据&#xff1a;一段代码读取Chrome存储的所有账号密码和Cookie 本文再扩展介绍一下Chrome存储的其它一些隐私数据。 注&#xff1a;因为业务需要&#xff0c;简单调研了一些基本内容和存储路径&#xff0c;没有深入去研究&#xff0c;有啥…

新160个crackme - 002-abexcm5

运行分析 猜测需要输入正确序列号 PE分析 32位&#xff0c;ASM程序&#xff0c;无壳 静态分析 ida shift F12 &#xff0c;发现字符串定位主函数 分析主函数 lstrcat&#xff1a;拼接字符串 lstrcmpiA&#xff1a;比较字符串 动态调试 serial输入123456调试 发现序列号…

Codeforces Round 957 (Div. 3)(A~D题)

A. Only Pluses 思路: 优先增加最小的数&#xff0c;它们的乘积会是最优,假如只有两个数a和b&#xff0c;b>a&#xff0c;那么a 1&#xff0c;就增加一份b。如果b 1&#xff0c;只能增加1份a。因为 b > a&#xff0c;所以增加小的数是最优的。 代码: #include<bi…

Spring Boot集成groovy快速入门Demo

1.什么是groovy&#xff1f; Groovy 是构建在 JVM 上的一个轻量级却强大的动态语言&#xff0c;它结合了 Python、Ruby 和 Smalltalk 的许多强大的特性。 Groovy 就是用 Java 写的&#xff0c;Groovy 语法与 Java 语法类似&#xff0c;Groovy 代码能够与 Java 代码很好地结合&…

STM32MP135裸机编程:定时器内核时钟频率计算方法

0 工具准备 STM32MP13xx参考手册 1 定时器内核时钟频率计算方法 1.1 定时器分组 STM32MP135的定时器按照时钟源不同分成了三组&#xff0c;如下&#xff1a; APB1: APB2: APB6&#xff1a; 1.2 定时器内核时钟频率计算方法 APB1DIV是APB1的分频系数&#xff0c;APB2DIV、…

python双下划线怎么打

连续按键盘上的“shift_”键两次即可&#xff0c;不同编辑器可能显示会不太一样。像图1中那样没连起来也是对的&#xff0c;没有语法错误。

基于python豆瓣电影爬虫数据可视化分析推荐系统(完整系统源码+数据库+详细文档+论文+详细部署教程)

文章目录 基于python豆瓣电影爬虫数据可视化分析推荐系统&#xff08;完整系统源码数据库详细文档论文详细部署教程&#xff09;一、 选题背景二、研究目的三、开发技术介绍1、Django框架2、LDA3、机器学习推荐算法4、大数据爬虫5、大数据Echarts可视化 四、系统设计思想五、部…

C++ | Leetcode C++题解之第235题二叉搜索树的最近公共祖先

题目&#xff1a; 题解&#xff1a; class Solution { public:TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {TreeNode* ancestor root;while (true) {if (p->val < ancestor->val && q->val < ancestor->val) {anc…

贪心算法案例

1.买卖股票的最佳时机 给定一个数组 prices &#xff0c;它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。 你只能选择 某一天 买入这只股票&#xff0c;并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。 返回你可以从这笔…

代码随想录算法训练营第31天|LeetCode 56. 合并区间、738.单调递增的数字、968.监控二叉树

1. LeetCode 56. 合并区间 题目链接&#xff1a;https://leetcode.cn/problems/merge-intervals/description/ 文章链接&#xff1a;https://programmercarl.com/0056.合并区间.html 视频链接&#xff1a;https://www.bilibili.com/video/BV1wx4y157nD 思路&#xff1a; 本题关…

SpringBoot新手快速入门系列教程十一:自动生成API文档,Springboot3.x集成SpringDoc

本次项目我们用Maven来做&#xff0c;最近发现gradle其实很多项目的支持比较差&#xff0c;所以项目还是用Maven来新建项目。对比了市面上的几种API生成第三方库&#xff0c;只有springdoc 是能够按照文档就能部署出来的。 官网&#xff1a; OpenAPI 3 Library for spring-bo…

链接追踪系列-04.linux服务器docker安装elk

[rootVM-24-17-centos ~]# cat /proc/sys/vm/max_map_count 65530 [rootVM-24-17-centos ~]# sysctl -w vm.max_map_count262144 vm.max_map_count 262144 #先创建出相应目录&#xff1a;/opt/dockerV/es/…docker run -e ES_JAVA_OPTS"-Xms512m -Xmx512m" -d -p 92…

【流媒体】 通过ffmpeg硬解码拉流RTSP并播放

简介 目前RTSP拉流是网络摄像头获取图片数据常用的方法&#xff0c;但通过CPU软解码的方式不仅延时高且十分占用资源&#xff0c;本文提供了一种从网络摄像头RTSP硬解码的拉流的方法&#xff0c;并且提供python代码以便从网络摄像头获取图片进行后续算法处理。 下载ffmpeg F…

2024-07-15 Unity插件 Odin Inspector3 —— Button Attributes

文章目录 1 说明2 Button 特性2.1 Button2.2 ButtonGroup2.3 EnumPaging2.4 EnumToggleButtons2.5 InlineButton2.6 ResponsiveButtonGroup 1 说明 ​ 本章介绍 Odin Inspector 插件中有关 Button 特性的使用方法。 2 Button 特性 2.1 Button 依据方法&#xff0c;在 Inspec…

QT控件篇三

一、微调框 微调框&#xff08;QSpinBox&#xff09;是一个常用的Qt控件&#xff0c;允许用户通过增加或减少值来输入数字。分为两种, 整型-QSpinBox 浮点 QDoubleSpinBoxQSpinBox&#xff08;微调框&#xff09;的 setSingleStep 函数可以用来设置每次调整的步长&#xff08;…

【人工智能】人工智能与传统美工结合,AI美工的详细解析。

AI美工是一个结合了人工智能技术与美工设计的岗位&#xff0c;它利用AI工具和技术来辅助或完成美工设计的各项工作。以下是对AI美工的详细解析&#xff1a; 一、定义与职责 AI美工是指能够熟练使用AI工具和技术&#xff0c;如Midjourney、StableDiffusion等AIGC&#xff08;人…

2024安全行业大模型技术应用态势发展报告

以上是资料简介和目录&#xff0c;如需下载&#xff0c;请前往星球获取&#xff1a;https://t.zsxq.com/dH9bu

Python爬虫入门篇学习记录

免责声明 本文的爬虫知识仅用于合法和合理的数据收集&#xff0c;使用者需遵守相关法律法规及目标网站的爬取规则&#xff0c;尊重数据隐私&#xff0c;合理设置访问频率&#xff0c;不得用于非法目的或侵犯他人权益。因使用网络爬虫产生的任何法律纠纷或损失&#xff0c;由使用…

计算机网络之网络互连

1.什么是网络互连 1.1网络互连的目的 将两个或者两个以上具有独立自治能力的计算机网络连接起来&#xff0c;实现数据流通&#xff0c;扩大资源共享范围&#xff0c;或者容纳更多用户。 网络互连包括&#xff1a; 同构网络、异构网络的互连&#xff0c; 局域网与局域网&…

【Linux】多线程_5

文章目录 九、多线程6. 条件变量7. 生产者消费者模型 未完待续 九、多线程 6. 条件变量 在多线程编程中&#xff0c;一个或多个线程可能需要等待某个条件的发生&#xff0c;然后才能继续执行&#xff0c;而不是一直忙等。这种等待通常会占用CPU资源。条件变量提供了一种机制&…