直接插入排序(C++实现)

news2024/11/6 8:17:14

文章目录

  • 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)

此外,从代码中可以看到,即使遇到了关键字相同的两条记录,这两条记录的相对顺序也不会发生改变,所以这个排序算法是稳定的。直接插入排序比较适合待排序记录数量比较少时的情形,如果待排序记录的数量比较大,就要考虑通过减少比较和移动数据次数对这种排序实现方法进行优化。

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

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

相关文章

Vue系列之入门篇

前言&#xff1a; 目录 一&#xff0c;关于Vue的简介 1.什么是Vue&#xff1f; 2.使用Vue框架的好处&#xff1f; 3. 库和框架的区别&#xff1a; 4. MVVM的介绍 5.Vue的入门案例 二&#xff0c;Vue的生命周期 一&#xff0c;关于Vue的简介 1.什么是Vue&#xff1f; Vu…

详解混合类型文件(Polyglot文件)的应用生成与检测

1. 引入 混合类型文件&#xff08;Polyglot文件&#xff09;&#xff0c;是指一个文件&#xff0c;既可以是合法的A类型&#xff0c;也可以是合法的B类型。 比如参考3中的文件&#xff0c;是一个html文件&#xff0c;可以用浏览器正常打开&#xff1b;它也是一个一个.jar文件&…

来看看Javadoc(文档注释)详解

Java 支持 3 种注释&#xff0c;分别是单行注释、多行注释和文档注释。文档注释以/**开头&#xff0c;并以*/结束&#xff0c;可以通过 Javadoc 生成 API 帮助文档&#xff0c;Java 帮助文档主要用来说明类、成员变量和方法的功能。 文档注释只放在类、接口、成员变量、方法之前…

代码随想录算法训练营第53天 | ● 1143.最长公共子序列 ● 1035.不相交的线 ● 53. 最大子序和

文章目录 前言一、1143.最长公共子序列二、1035.不相交的线三、53. 最大子序和总结 前言 动态规划 一、1143.最长公共子序列 确定dp数组&#xff08;dp table&#xff09;以及下标的含义 dp[i][j]&#xff1a;长度为[0, i - 1]的字符串text1与长度为[0, j - 1]的字符串text2的…

​云南财经大学《乡村振兴战略下传统村落文化旅游设计》许少辉八一著作

​云南财经大学《乡村振兴战略下传统村落文化旅游设计》许少辉八一著作

掌握这5种方法,让你的新AirPods充电盒更耐用!

每次AirPods充电盒落地时&#xff0c;你都会呼吸急促吗&#xff1f;无论我使用的是旧一代的AirPods还是最新的AirPod Pro 2&#xff0c;我都关心它们的保存状况&#xff0c;并尽力保护这些脆弱设备的安全。我想我对AirPods Pro 2的新充电盒也会有同样的感受&#xff0c;它在9月…

学校项目培训之Carla仿真平台之安装Carla

官网&#xff1a;http://carla.org/ 写在前面 由于安装都写了很多东西&#xff0c;所以我单独将安装弄出来记录一下。 如果你在安装9.12版本的时候遇到了很多问题&#xff0c;你可以考虑以下几点&#xff1a; - 楼梯可能不太行&#xff0c;需要更换&#xff0c;这是我实践得到的…

英语——记忆篇——谐音法+拼音法

中小学单词&#xff1a; 谐音法&#xff1a; 1.issue n.问题&#xff1b;&#xff08;杂志、报刊的&#xff09;一期&#xff1b;v.发行 谐音“一休”&#xff1b;想象聪明的一休很会解决问题&#xff0c;发行了一期杂志专门描述他解决问题的方法&#xff1b; issue 问题&…

电脑大文件删除了能恢复吗 电脑大文件删除了怎么恢复

在日常办公中&#xff0c;电脑是必不可少的办公工具&#xff0c;电脑能够帮助我们储存大量的大文件&#xff0c;但是有时候可能会因为一些误操作或者电脑故障等情况&#xff0c;导致一些电脑大文件的丢失&#xff0c;所以今天就和大家分享一下&#xff0c;电脑大文件删除了能恢…

[UE]碰撞和Trace检测

UE的碰撞和Trace检测 基础概念碰撞相关概念Overlap和Hit事件概念和条件使用示例 Trace检测引擎 World.h 中的TraceUKismetSystemLibrary 中的 TraceHitResultTrace示例LineTraceSphereTraceSingleBoxSweepSphereTraceCapsuleTrace 记录SetActorLocation中的Sweep和Teleport为啥…

CocosCreator3.8研究笔记(十九)CocosCreator UI组件(三)

前面的文章已经介绍了Layout 组件 、ScrollView 组件 、PageView 组件 。 想了解的朋友&#xff0c;请查看 CocosCreator3.8研究笔记&#xff08;十八&#xff09;CocosCreator UI组件&#xff08;二&#xff09;。 今天我们主要介绍CocosCreator 常用组件&#xff1a;Butt…

Windows 10 Enterprise LTSC 2021 (x86) - DVD (Chinese-Simplified)文件分享

Windows 10 Enterprise LTSC 2021 (x64) - DVD (Chinese-Simplified) SW_DVD9_WIN_ENT_LTSC_2021_64BIT_ChnSimp_MLF_X22-84402.ISO 镜像文件&#xff1a; 链接&#xff1a;https://pan.quark.cn/s/2f8f61ec4a98 Windows 10 Enterprise LTSC 2021 (x86) - DVD (Chinese-Simpli…

辐射威胁:揭示辐射对人体健康和肠道菌群的影响及防护

谷禾健康 辐射对人体的影响是一个长期以来备受关注的问题。长时间暴露在辐射环境下可能会导致细胞损伤、突变和癌症等健康问题。 辐射包括电离辐射&#xff08;X光机、CT、伽马刀、钴60治疗机、碘-131&#xff09;和非电离辐射&#xff08;手机辐射、微波炉、电热毯、高压电塔、…

LeetCode(力扣)968. 监控二叉树Python

LeetCode968. 监控二叉树 题目链接代码 题目链接 https://leetcode.cn/problems/binary-tree-cameras/description/ 代码 # Definition for a binary tree node. # class TreeNode: # def __init__(self, val0, leftNone, rightNone): # self.val val # …

翻牌闯关游戏

翻牌闯关游戏 3关&#xff1a;关卡由少至多12格、20格、30格图案&#xff1a;12个玩法&#xff1a;点击两张卡牌&#xff0c;图案一到即可消除掉 记忆时长(毫秒)&#xff1a;memoryDurationTime:5000 可配置&#xff0c;默认5000 提示游戏玩法&#xff1a;showTipsFlag:1 可…

算法宝典2——Java版本(此系列持续更新,这篇文章目前3道)(有题目的跳转链接)(此份宝典包含了二叉树的算法题)

注&#xff1a;由于字数的限制&#xff0c;我打算把算法宝典做成一个系列&#xff0c;一篇文章就20题&#xff01;&#xff01;&#xff01; 目录 一、二叉树的算法题&#xff08;目前3道&#xff09; 1. 平衡二叉树&#xff08;力扣&#xff09; 2. 对称二叉树&#xff0…

合肥先进光源国家重大科技基础设施项目及配套工程启动会纪念

合肥先进光源国家重大科技基础设施项目及配套工程启动会纪念 卡西莫多 合肥长丰岗集里 肥鸭从此别泥塘 先平场地设围栏 进而工地筑基忙 光阴似箭指日争 源流汇智山水长 国器西北扩新地 家校又添新区园 重器托举有群力 大步穿梭两地间 科教兴邦大国策 技术盈身坦荡行…

Sourcetree 无法打开/闪退问题

Sourcetree在某次开机以后无法打开或者是闪退。 Sourcetree是一款Git的可视化图形管理界面,提供了Windows和Mac的免费Git客户端,很方便的管理项目的代码版本 出现问题的环境 win11&#xff0c;sourcTree版本&#xff1a;3.4.12.0 在开始菜单搜索sourcetree&#xff0c;打开…

Golang中的GMP调度模型

GMP调度模型 Golang调度器的由来 单进程时代不需要调度器 1.单一的执行流程&#xff0c;计算机只能一个任务一个任务处理。 2.进程阻塞所带来的CPU时间浪费。 后来操作系统就具有了最早的并发能力&#xff1a;多进程并发&#xff0c;当一个进程阻塞的时候&#xff0c;切换…

polygon yolo

[1] : github: https://github.com/HRan2004/Yolo-ArbPolygon [2] https://github.com/XinzeLee/PolygonObjectDetection [3] https://github.com/AlbinZhu/yolov7-polygon-detection 链接&#xff1a;https://pan.baidu.com/s/1Zpl1bIGfMli6p5LQdbET0w?pwddw2b 提取码&#…