直接插入排序(C++实现)
文章目录
- 1. 基础概念
- 🍑 内部排序和外部排序
- 2. 直接插入排序
- 3. 动图演示
- 4. 代码实现
- 5. 性能分析
无论是日常生活还是很多科学领域当中,排序都是会经常面对的问题,比如按成绩对学校的学生排序,按薪水多少对公司员工排序等。
根据在排序过程中待排序的数据是否全部被载入到内存中,排序分为内部排序和外部排序。下面各种排序算法涉及的主要是内部排序,包含各种经典的内部排序算法。
将按照对 数据操作方式 的不同来分类讲解。
1. 基础概念
所谓排序(Sort),就是将一组数据(也称元素),按照一定的规则调换位置,使这组数据按照递增或递减的顺序重新排列。例如数据库中有一个 “学生表”,可以针对该表中的 “年龄” 字段进行排序,那么这个待排序的字段就称为键(key)或者关键字。排序一般是为了让查找数据的效率变得更高。
这里涉及一个排序算法的稳定性问题。依旧以 “学生表” 为例,假如表中数据如下:
在上图所示的学生表中,需要针对表中的 “年龄” 字段(键)按照某种排序算法进行递减或者递增排序。此时(排序前)张三和赵六的年龄都是 27 岁且张三这条记录位于赵六之前,而在排序后,如果张三这条记录依旧位于赵六之前,那我们就说这种排序算法是 稳定 的,如下图所示:
反之,如果排序后赵六这条记录位于张三之前,那我们就说这种排序算法是不稳定的,如下图所示:
所以,所谓 稳定的排序算法,指的就是关键字相同的元素在排序后相对位置不变。针对排序算法的稳定性有两点说明:
- 有些排序算法,基于其实现的原理,确实是无法做到稳定,这种算法当然称为不稳定。
- 有些排序算法,是可以做到稳定的。但是,如果稍微调整一下它的实现代码,让它变得不稳定也是很容易的。
- 当无法判断一个算法是否稳定时,可以书写测试代码来进行稳定性测试。
🍑 内部排序和外部排序
在排序算法实现时,虽然很多时候都是用整数进行举例,但在真正的项目中,往往要排序的并不是单纯的数字,而是一组对象,按照对象的某个关键字来排序,所以排序的稳定性也是一个必须要考虑的问题。
想象一下,两个用户在某个电子商城中购买了相同的商品,他们的下单时间一个在前一个在后,如果按照订单中商品价格排序,那么这两张订单因为购买的是相同的商品,价格相同,所以排序后应该会相邻,但因为采用稳定的排序算法,所以排序后这两个订单依旧会按照原来下单的时间顺序排列。
根据在排序过程中待排序的数据是否全部被载入到内存中,排序分为 内部排序(内排序) 和 外部排序(外排序)。
内部排序 是指:在整个排序过程中,待排序的所有数据(记录)都被载入到内存中。
外部排序 是指:在整个排序过程中,因为排序的数据太多(比如大数据)而不能同时载入到内存中,导致整个的排序过程需要在内存和外存(比如磁盘)之间进行多次数据交换。因为磁盘和内存的读写速度相比往往要慢上数十甚至数百倍,所以外部排序往往需要尽量减少磁盘的读写次数。
这些经典的内部排序算法有好多种,每种排序算法都有相应的优缺点,适合在不同的情况下使用。而这些算法的分类方式也有很多种,比如按照数据操作方式来划分,按照时间复杂度来划分等。
大部分经典排序算法都仅适用于顺序存储的线性表,而不太适用于链式存储的线性表。对于大多数排序算法在排序过程中有两种基本操作:
- 比较两个关键字的大小
- 将记录从一个位置移动到另外一个位置
一般来说,比较两个关键字大小是必须的,但将记录从一个位置移动到另外一个位置也许可以通过一些变通的方式来实现,从而提高排序算法的执行效率。而效率对于排序算法当然是最重要的。
2. 直接插入排序
所谓 插入类 排序,就是向有序序列(已经排好序的序列)中依据关键字的比较结果寻找合适的位置,插入新的记录,构成新的有序序列,直至所有记录插入完毕。
插入类排序可以细分为很多种,每种之间的差别主要体现在插入位置的查找以及插入新数据导致原有数据的移动方面。我们先来看第一种。
直接插入排序: 每次将一个记录按其关键字的大小插入到已经排好序的序列中,直至全部记录插入完毕。这种排序方式将待排数据依次和数组中已经排好序的记录进行比较并确定自己的位置。
假设现在有 10 个元素的整型数组:int arr[] = {16, 1, 45, 23, 99, 2, 18, 67, 42, 10}
,现在,我们希望对这个数组中的元素进行从小到大排序。
根据直接插入排序算法的思想,我们首先认为数组中的第 1 个元素(16)包含在已经排好序的序列中。然后从数组中的第 2 个元素开始,依次针对数组中的元素寻找合适的位置插入到已经排好序的序列中就行了。
所以,就会有下面的操作步骤:
- 先看 1,1 比 16 小,所以 1 插入到 16 之前,16 后移。这是因为已经排好序的序列中目前只有 16,所以只需要将 16 后移,数组 arr 目前的情形是:
{1, 16, 45, 23, 99, 2, 18, 67, 42, 10}
。 - 接着看 45,45 比 1 和 16 都大所以 45 位置不动,数组 arr 目前的情形是:
{1, 16, 45, 23, 99, 2, 18, 67, 42, 10}
。 - 接着看 23,23 比 16 大但比 45 小,所以 23 插入到 45 之前,45 后移,数组 arr 目前的情形是:
{1, 16, 23, 45, 99, 2, 18, 67, 42, 10}
。 - 接着看 99,99 目前最大,所以位置不动,数组 arr 目前的情形是:
{1, 16, 23, 45, 99, 2, 18, 67, 42, 10}
。 - 接着看 2,2 比 1 大但比 16 小,所以 2 插入到 16 之前,16、23、45、99 依次后移,数组 arr 目前的情形是:
{1, 2, 16, 23, 45, 99, 18, 67, 42, 10}
。 - 接着看 18,18 比 16 大但比 23 小,所以 18 插入到 23 之前,23、45、99 依次后移,数组 arr 目前的情形是:
{1, 2, 16, 18, 23, 45, 99, 67, 42, 10}
。 - 接着看 67,67 比 45 大但比 99 小,所以 67 插入到 99 之前,99 后移,数组 arr 目前的情形是:
{1, 2, 16, 18, 23, 45, 67, 99, 42, 10}
。 - 接着看 42,42 比 23 大但比 45 小,所以 42 插入到 45 之前,45、67、99 依次后移,数组 arr 目前的情形是:
{1, 2, 16, 18, 23, 42, 45, 67, 99, 10}
。 - 接着看 10,10 比 2 大但比 16 小,所以 10 插入到 16 之前,16、18、23、42、45、67、99 依次后移,数组 arr 目前的情形是:
{1, 2, 10, 16, 18, 23, 42, 45, 67, 99}
。
以上就是直接插入排序算法的完整工作过程描述。
把一个无序数组 {16, 1, 45, 23, 99, 2, 18, 67, 42, 10}
最终变得有序 {1, 2, 10, 16, 18, 23, 42, 45, 67, 99}
,只需要从前向后遍历数组中的每个元素,再为每个元素找到合适的位置就可以了。
3. 动图演示
这里我对 21, 3, 6, 17, 12, 1, 49, 10, 45, 43
这组数据进行直接插入排序,每趟的排序过程如下:
4. 代码实现
直接插入排序的实现代码有很多种,比如有的资料会采用哨兵位的方式来实现。所谓哨兵位,就是在数据结构中留出一个特殊位置,避免在算法实现过程中引入临时变量。下面采用的是非哨兵的实现方式。
代码实现
//直接插入排序(从小到大)
template<typename T>
void InsertSort(T arr[], int len) {if (len <= 1) //不超过1个元素的数组,没必要排序return;for (int i = 1; i < len; ++i) //从第2个元素(下标为1)开始比较{if (arr[i] < arr[i - 1]){T temp = arr[i]; //暂存arr[i]值,防止后续移动元素时值被覆盖 int j;for (j = i - 1; j >= 0 && arr[j] > temp; --j) //检查所有前面排好序的元素{arr[j + 1] = arr[j]; //所有大于temp的元素都向后移动}arr[j + 1] = temp; //复制数据到插入位置,注意j因为被减了1,这里加回来}}return;
}
在主函数中,加入测试代码
int main()
{int arr[] = {16, 1, 45, 23, 99, 2, 18, 67, 42, 10}; int len = sizeof(arr) / sizeof(arr[0]); //数组中元素个数InsertSort(arr, len); //对数组元素进行直接插入排序//输出排好序的数组中元素内容cout << "直接插入排序结果为:";for (int i = 0; i < len; ++i) {cout << arr[i] << " ";}cout << endl;return 0;
}
运行结果如下:
5. 性能分析
从代码中可以看到,直接插入排序实现比较简单。因为只有一些临时变量参与运算,所以其空间复杂度为 O ( 1 ) O(1) O(1),对于时间复杂度方面,主要来自于关键字比较和位置移动操作。对于具有 n 个元素的数组,外循环次数是 n-1 次。
在最好的情况下,即数组中元素已经是排好序的情况下,外循环需要循环 n-1 次,每次也只需要一次关键字比较(if (arr[i] < arr[i - 1])
语句),不需要进行任何元素移动,所以,最好情况时间复杂度为 O ( n ) O(n) O(n)。
在最坏情况下,即数组中元素正好是逆序排列的情况下,外循环需要循环 n-1 次,每次循环都要比较和移动元素若干次,所以最坏情况时间复杂度为 O ( n 2 ) O(n^2) O(n2)。平均情况时间复杂度也为 O ( n 2 ) O(n^2) O(n2)。
此外,从代码中可以看到,即使遇到了关键字相同的两条记录,这两条记录的相对顺序也不会发生改变,所以这个排序算法是稳定的。直接插入排序比较适合待排序记录数量比较少时的情形,如果待排序记录的数量比较大,就要考虑通过减少比较和移动数据次数对这种排序实现方法进行优化。
相关文章:
直接插入排序(C++实现)
文章目录 1. 基础概念🍑 内部排序和外部排序 2. 直接插入排序3. 动图演示4. 代码实现5. 性能分析 无论是日常生活还是很多科学领域当中,排序都是会经常面对的问题,比如按成绩对学校的学生排序,按薪水多少对公司员工排序等。 根据…...
【k8s】Pod 的钩子
Kubernetes(K8s)中的 Pod 可以使用以下几种勾子(钩子)来执行在容器生命周期的不同阶段运行的操作: PostStart(启动后):该勾子在容器启动之后立即运行。它可以用于在容器内执行一些初…...
MCU软核 3. Xilinx Artix7上运行cortex-m3软核
0. 环境 - win10 vivado 2018.3 keil mdk - jlink - XC7A35TV12 1. 下载资料 https://keilpack.azureedge.net/pack/Keil.V2M-MPS2_DSx_BSP.1.1.0.pack https://gitee.com/whik/cortex_m3_on_xc7a100t 2. vivado 2018 Create Project -> Next -> -> Project n…...
基于SpringbootShiro实现的CAS单点登录
概述 单点登录(Single Sign On,SSO)是一种登录管理机制,主要用于多系统集成,即在多个系统中,用户只需要到一个中央服务器登录一次即可访问这些系统中的任何一个,无须多次登录。常见的例子就是,…...
SocketTool V4.0 使用说明
TCP/UDP Socket 调 试 工 具 提 供 了 TCP Server,TCP Client,UDP Server,UDP Client,UDP Group 五种 Socket 调试方案。 下面是一份简要的使用流程: TCP 通信测试: 1) 创建 TCP Server 选中左方的 TCP Server, 然后点击 ”创建 ”按钮,软件弹…...
Jenkins结合allure生成测试报告
前言: 我们在做自动化测试的过程中最重要的肯定是报告的输出啦,最近几年allure可以说是最最主流报告展示工具啦。 一、服务端安装allure 在安装Jenkins的机器 安装allure,我们在Jenkins上能跑动前提是在对应服务器上代码能正常运行…...
【Linux】缓冲区/回车换行
1、缓冲区 C程序默认有输出缓冲区。数据输出时,被及时看到,是立马刷新了;如果没被看到,是被暂存在数据缓冲区中。fflush(stdout); 【强制刷新】\n【行刷新,也是一种刷新方式】 2、回车换行 \n【回车换行】输入完一行内…...
Java手写插入排序和算法案例拓展
1. Java手写插入排序和算法案例拓展 1.1 算法思维导图 #mermaid-svg-jIZ3LAdg1NLcOvaM {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-jIZ3LAdg1NLcOvaM .error-icon{fill:#552222;}#mermaid-svg-jIZ3LAdg1NLcOvaM…...
Python Opencv实践 - 视频文件操作
参考资料: 视频处理VideoCapture类---OpenCV-Python开发指南(38)_python opencv videocapture_李元静的博客-CSDN博客 OpenCV VideoCapture.get()参数详解 - 简书FOURCC四字符码对照表_4fvcc_Kellybook的博客-CSDN博客 import cv2 as cv im…...
HCS 中的一些概念(二)
一、Service OM 1、首页(资源状态) 2、服务列表 计算资源:计算资源又分为可用分区(AZ)、规格和虚拟机组,可在此处创建虚拟机、虚拟机组、主机组和规格 网络资源:网络资源又分为物理网络…...
Scanner类用法(学习笔记)
Scanner类用法(学习笔记,后续会补充) 1.next()用法 package com.yushifu.scanner; import java.util.Scanner;//util java工具包 //Scanner类(获取用户的输入) Scanner s new Scanner&#…...
idea2021.1.3版本双击启动,没反应
今天打开电脑,点开idea,界面悬在这里,几秒然后就是没了。然后就一直打不开idea了。 然后又是卸载重装,又是删除缓存文件。我把电脑关于idea的文件全都删除了 。重新安装后(首次运行倒是可以打开,但是关掉id…...
MC-4/11/01/400 ELAU 软件允许用户完全访问相机设置
MC-4/11/01/400 ELAU 软件允许用户完全访问相机设置 一个完整的Sentinel模具保护解决方案包括一到四台冲击式摄像机、专用红外LED照明和镜头、Sentinel软件以及所有与模压机连接的必要互连组件。摄像机支架基于磁性,可快速、安全、灵活地部署。此外,一个…...
Error contacting service. It is probably not running.问题解决
一 问题描述 Error contacting service. It is probably not running. 查看zookeeper 目录下数据目录下的zookeeper.out 如果你没找到这个目录那么 OK 你的问题就是 zoo.cfg 文件中数据目录设置错误 zookeeper.out下报错 ERROR [main:QuorumPeerMain86] - Invalid config,…...
01_网络编程_传统IO
网络编程 1.什么是网络编程 在网络通信协议下,不同计算机上运行的程序,进行的数据传输。 如果想把一个计算的结果,或者是电脑上的文件通过网络传递给你的朋友,就需要用到网络编程。 在实际生活中,网络通信无处不在…...
vue 检查指定路由是否存在
今天路由跳转报错了 RangeError: Maximum call stack size exceeded 但显然 我的代码只有一个简单的路由跳转 并没有很大的的堆栈数据操作 所以 我就联想到了 会不会是因为路由不存在 我们可以通过 console.log(this.$router.options.routes)输出整个路由对象类看一下 或者…...
自动化办公更简单了:新版python-office,有哪些更新?
#职场经验谈# 大家好,这里是程序员晚枫,小破站/小红薯都叫这个名。 去年4月开源了一个Python自动化办公项目:python-office,GitHub和Gitee都能看到。1行代码实现复杂的自动化办公任务,帮助不懂代码的小白,…...
windows flask服务卡死的问题
windows flask服务卡死的问题 最近的工作中,需要用python写一个flask服务,供C端调用,但是偶尔服务会卡住,只接收数据但不进行处理,不过CtrlC后又可以继续运行。 查看了网上的一些解决方法,但似乎都没有什…...
项目上线部署--》服务器部署流程(一)
目录 🌟准备工作 服务器购买 域名购买 域名解析(配置 DNS) 🌟服务器环境搭建 配置服务器 安装 CentOS 开发人员相关包 编辑 配置免密登陆 🌟写在最后 🌟准备工作 服务器购买 国内服务器&#x…...
Python:函数调用的实参
相关阅读 Python专栏https://blog.csdn.net/weixin_45791458/category_12403403.html 调用就是附带可能为空的一系列参数来执行一个可调用对象 (例如函数),它的语法的BNF范式如下所示,有关BNF范式的规则,可以参考之前…...
174. 地下城游戏 -- 动规
174. 地下城游戏 class CalculateMinimumHP:"""174. 地下城游戏https://leetcode.cn/problems/dungeon-game/"""def solution(self, dungeon: List[List[int]]) -> int:# 我们想计算左上⻆到右下⻆所需的最⼩⽣命值m, n len(dungeon), len(d…...
js实现websocket服务端和客户端
天行健,君子以自强不息;地势坤,君子以厚德载物。 每个人都有惰性,但不断学习是好好生活的根本,共勉! 文章均为学习整理笔记,分享记录为主,如有错误请指正,共同学习进步。…...
qt qml RadioButton如何设置字体颜色,style提示找不到怎么办?
qt QML中设置RadioButton的字体颜色,可以使用RadioButton的label属性来设置文本的样式。下面是一个示例代码: import QtQuick 2.6 import QtQuick.Controls 2.2 import QtQuick.Controls 1.4 as Controls1_4 import QtQuick.Controls.Styles 1.4 import…...
Docker 的使用
一、Docker 的作用和优势 软件集装箱化平台,可让开发者构建应用程序时,将它与环境一起打包到一个容器中,发布应用到任意平台中。 能在单台机器上运行多个Docker微容器,而每个微容器里都有一个微服务或独立应用, 如&am…...
【无公网IP内网穿透】Java支付宝沙箱环境支付,SDK接口远程调试
目录 1.测试环境 2.本地配置 3. 内网穿透 3.1 下载安装cpolar内网穿透 3.2 创建隧道 4. 测试公网访问 5. 配置固定二级子域名 5.1 保留一个二级子域名 5.2 配置二级子域名 6. 使用固定二级子域名进行访问 1.测试环境 MavenSpring bootJdk 1.8 2.本地配置 获取支付…...
axios 用formData的方式请求数据
需求:使用axios库用来做http数据传输。 问题:传递数据的时候不是直接通过json的方式来传输的数据,二是通过formData的方式 解决: axios 请求头设置,Content-Type "Content-Type": "application/x-w…...
Mapbox加载arcgis的底图
成果图 这种底图基本上都是按照raster来加载的,主要就是知道地址了,拼参数 具体参数请参考官网 https://developers.arcgis.com/rest/services-reference/enterprise/export-map.htm 源码 我的服务列表是这样的 http://XXXX:XXXX/arcgis/rest/services/…...
(20)线程安全问题:Lock,双锁问题,Monitor,死锁
一、Lock 1、用多线程给变量自增,10000个线程自增 List<Task> tasks new List<Task>();int AsyncNum 0;for (int i 0; i < 10000; i){tasks.Add(Task.Run(() >{AsyncNum;}));}Task.WaitAll(tasks.ToArray());Console.WriteLine($"AsyncNu…...
医院如何实现安全又稳定的跨网文件数据交换呢?
随着医疗信息化的发展,医院之间需要频繁地进行文件数据交换,以实现诊疗、科研、管理等方面的协同和共享。然而,由于医院网络环境的复杂性和敏感性,跨网文件数据交换面临着安全性和稳定性的双重挑战。如何在保证文件数据不被泄露、…...
关于老项目从JDK8升级到JDK17所需要注意的细节
文章目录 ☀️1.关于老项目从JDK8升级到JDK17所需要注意的细节🌸1.1.更新JDK🌸1.2.修改Idea中的JDK版本🌸1.3.关于修改过程中遇到的异常🌸1.4.IDEA工具栏操作Maven正常,但使用mvn命令运行就报错 ☀️1.关于老项目从JDK…...
树莓派做网站/互联网培训
本篇文章给大家带来的内容是关于MySQL如何通过实例化对象参数查询数据 ?(源代码),有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。public static string QueryByEntity(T t) where T : new(){ string resultstr s…...
域名停靠app盘他免费下载/免费seo网站自动推广软件
网络时代,一个人可以完成好多从前只有一个团队才可以完成的任务。比如游戏开发。现在开发游戏主流引擎是UNREAL 4或者UNITY。比如大家耳熟能详的吃鸡(PUBG)就是用的UNREAL 4(虚拟4)引擎开发的。王者荣耀是用UNITY 3D开…...
教做幼儿菜谱菜的网站/成都搜索优化排名公司
1 三次握手 TCP是面向连接的,无论哪一方向另一方发送数据之前,都必须先在双方之间建立一条连接。在TCP/IP协议中,TCP 协议提供可靠的连接服务,连接是通过三次握手🤝进行初始化的。三次握手🤝的目的是同步连…...
重庆做商城网站/上海有什么seo公司
来自:啤酒大泡泡链接:cnblogs.com/hzg110/p/6936101.html正文 目前所有的项目都在使用maven,可是一直没有时间去整理学习,这两天正好有时间,好好的整理一下。一、为什么使用Maven这样的构建工具【why】① 一个项目就…...
怎样做返利网站/千牛怎么做免费推广引流
前言 在前一篇文章中我们学习了Java虚拟机的结构原理与运行时数据区域,那么我们大概知道了Java虚拟机的内存的概况,那么内存中的数据是如何创建和访问的呢?这篇文章会给你答案。 1.对象的创建 对象的创建通常是通过new一个对象而已࿰…...
ui设计的软件/宁波seo公司网站推广
各位医学方的朋友,大家好。我是Flyman!做过下游分析的小伙伴都知道富集分析的重要性,生信类文章大家总会在最后一步针对我们前面筛选出来的差异基因做一下GO/KEGG富集分析,研究一下他们参与到什么信号通路上或者参与什么生物学过程…...