插入排序与计数排序详解

news2024/12/23 12:33:59

在 C++ 编程中,排序算法是非常基础且重要的知识。今天我们就来深入探讨两种常见的排序算法:插入排序和计数排序,包括它们的代码实现、时间复杂度、空间复杂度、稳定性分析以及是否有优化提升的空间。

一、插入排序

插入排序(Insertion Sort)是一种简单直观的排序算法,它的工作原理类似于我们扑克牌理牌的过程,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。

1. 代码实现

#include <iostream>
#include <vector>

void insertionSort(std::vector<int>& arr) {
	int n = arr.size();
	for (int i = 1; i < n; ++i) {
		int key = arr[i];
		int j = i - 1;
		while (j >= 0 && arr[j] > key) {
			arr[j + 1] = arr[j];
			j--;
		}
		arr[j + 1] = key;
	}
}

int main() {
	std::vector<int> arr = { 12, 11, 13, 5, 6 };
	insertionSort(arr);
	for (int num : arr)
		std::cout << num << " ";
	std::cout << std::endl;
	return 0;
}

在上述代码中,我们从数组的第二个元素开始,将当前元素 key 与已排序部分的元素依次比较,找到合适位置插入,使得已排序部分始终保持有序。

2. 时间复杂度

  • 最好情况:当输入数组已经有序时,每次比较只需一次,时间复杂度为 O(n),这里的n是数组的元素个数。因为只需要遍历一遍数组,每次比较都能确定当前元素位置无需移动。
  • 最坏情况:当输入数组是逆序时,对于每个元素,都需要与前面所有已排序元素比较并移动,时间复杂度为 O(n^{2})。
  • 平均情况:平均时间复杂度也是 O(n^{2}) ,因为在平均意义下,每个元素大约需要与已排序部分一半的元素进行比较和移动。

3. 空间复杂度

插入排序是原地排序算法,它只需要常数级别的额外空间,空间复杂度为O(1) 。因为在排序过程中,我们仅仅是在原数组上通过交换元素位置来实现排序,不需要额外开辟大量的数据存储空间。

4. 稳定性

插入排序是稳定的排序算法。所谓稳定,就是在排序过程中,如果两个元素相等,它们在排序前后的相对顺序保持不变。在插入排序代码中,当遇到相等元素时,我们不会交换它们的位置,只是将当前元素插入到合适位置,所以相等元素的相对顺序得以保留。

二、计数排序

计数排序(Counting Sort)是一种非比较排序算法,它适用于一定范围内的整数排序,利用元素值作为索引,统计每个元素出现的次数,然后根据统计结果将元素依次放回原数组。

1. 代码实现

#include <iostream>
#include <vector>
#include <algorithm>

void countingSort(std::vector<int>& arr) {
	int maxVal = *std::max_element(arr.begin(), arr.end());
	std::vector<int> count(maxVal + 1, 0);
	std::vector<int> output(arr.size(), 0);
	// 统计每个元素出现次数
	for (int num : arr)
		count[num]++;
	// 计算累计次数,确定元素在输出数组中的位置
	for (int i = 1; i <= maxVal; ++i)
		count[i] += count[i - 1];
	// 从后向前遍历原数组,将元素放入正确位置
	for (int i = arr.size() - 1; i >= 0; --i) {
		output[count[arr[i]] - 1] = arr[i];
		count[arr[i]]--;
	}
	// 将排序后结果复制回原数组
	for (int i = 0; i < arr.size(); ++i)
		arr[i] = output[i];
}

int main() {
	std::vector<int> arr = { 4, 2, 2, 8, 3, 3, 1 };
	countingSort(arr);
	for (int num : arr)
		std::cout << num << " ";
	std::cout << std::endl;
	return 0;
}

这段代码首先找出数组中的最大值,以此确定计数数组的大小。接着统计每个元素出现次数,再通过累计次数确定元素在输出数组中的最终位置,最后将排序好的元素放回原数组。

2. 时间复杂度

  • 计数排序的时间复杂度为O(n+m) ,其中n是输入数组的元素个数, m是输入数据的范围(最大值与最小值的差值加 1)。在统计元素出现次数和计算累计次数这两个步骤,都需要遍历一遍范围为m的计数数组,而遍历原数组需要n次操作,所以总的时间复杂度是两者之和。
  • 当m = n时,时间复杂度接近线性,这使得计数排序在特定场景下比基于比较的排序算法(如快速排序、归并排序等,时间复杂度O(nlogn)更快。

3. 空间复杂度

计数排序需要额外开辟计数数组和输出数组,所以空间复杂度为O(n+m) 。当数据范围 较大时,会占用较多的额外空间,这也是它的一个缺点。例如,如果要对 0 到 1000000 范围内的 100 个整数排序,就需要开辟一个长度为 1000001 的计数数组。

4. 稳定性

计数排序是稳定的排序算法。在代码实现中,从后向前遍历原数组放置元素到输出数组,相同元素后出现的会被放在靠后的位置,保证了稳定性。例如对于序列 [2, 1, 2],排序后仍然是 [1, 2, 2]。

总之,插入排序和计数排序各有优劣,在实际编程中,需要根据数据规模、数据范围、稳定性要求等因素综合选择合适的排序算法,以达到最优的性能表现。希望这篇文章能帮助大家深入理解这两种排序算法,在 C++ 编程中运用自如。

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

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

相关文章

示波器--UNI-T 优利德 UT4102C 使用介绍

示波器--UNI-T 优利德 UT4102C 使用介绍 1 介绍图示特点 2 UTP04示波器探头&#xff08;100M带宽&#xff09;3 功能介绍4 示例RS232 电平信号测试 参考 1 介绍 图示 特点 2GS/s的实时采样率&#xff1a;设备能够以每秒2吉萨&#xff08;Giga Samples per second&#xff09;…

【Mybatis-Plus】连表查询 逻辑删除 多租户

文章目录 连表查询逻辑删除多租户 连表查询 引入 mybatis-plus-join-boot-starter 依赖 <dependency><groupId>com.github.yulichang</groupId><artifactId>mybatis-plus-join-boot-starter</artifactId><version>1.5.1</version>…

【java面向对象编程】第七弹----Object类、类变量与类方法

笔上得来终觉浅,绝知此事要躬行 &#x1f525; 个人主页&#xff1a;星云爱编程 &#x1f525; 所属专栏&#xff1a;javase &#x1f337;追光的人&#xff0c;终会万丈光芒 &#x1f389;欢迎大家点赞&#x1f44d;评论&#x1f4dd;收藏⭐文章 目录 一、Object类 1.1equa…

【常微分方程讲义1.1】方程的种类发展与完备

方程在数学历史中不断发展&#xff0c;逐步趋于完备。从最初的简单代数方程到包含函数、算子甚至泛函的更复杂方程&#xff0c;数学家通过不断的扩展和深化&#xff0c;逐渐建立起更为丰富和多元的方程类型体系。方程的种类之所以不断演变&#xff0c;部分是因为解决实际问题的…

《庐山派从入门到...》板载按键启动!

《庐山派从入门到...》板载按键启动&#xff01; 《庐山派从入门到...》板载按键启动&#xff01; 视频内容大致如下 我们之前了解了GPIO的输出模式使用方法&#xff0c;并且成功点灯&#xff0c;很明显本篇要来分享的自然是GPIO的输入模式 正好回顾一下之前学的python基础包…

Android笔试面试题AI答之Android基础(3)

文章目录 1.谈一谈 Android 的安全机制一、系统架构层面的安全设计二、核心安全机制三、其他安全机制与措施 2.Android 的四大组件是哪四大&#xff1f;3.Android 的四大组件都需要在清单文件中注册吗&#xff1f;4.介绍几个常用的Linux命令一、文件和目录管理二、用户和权限管…

黑马商城项目—服务调用

使用起因 之前我们完成了拆分购物车模块,但当我们进行测试查询时: 我们注意到&#xff0c;其中与商品有关的几个字段中:最新状态和库存为默认值,最新价格为空&#xff01;这就是因为我们注释掉了查询购物车时&#xff0c;查询商品信息的相关代码。 那么&#xff0c;我们该如何…

RK356x bsp 5 - 海华AW-CM358SM Wi-Fi/Bt模组调试记录

文章目录 1、环境介绍2、目标3、海华AW-CM358SM3.1、基本信息3.2、支持SDIO3.03.3、电气特性 4、适配流程步骤5、让SDIO控制器工作&#xff0c;且可以扫到WIFI卡5.1、dts配置5.2、验证 6、Wi-Fi 适配6.1、dts配置6.2、驱动移植6.2.1、kernel menuconfig6.2.2、传统驱动移植6.2.…

VBA编程:自定义函数 - 字符串转Hex数据

目录 一、自定义函数二、语法将字符串转换为hex数据MID函数:返回一个字符串中指定位置和长度的子串LEN函数:返回一个字符串的长度(字符数)Asc函数三、定义变量和数据类型变量声明的基本语法常见的数据类型四、For循环基本语法五、&运算符一、自定义函数 定义:用户定义…

工业大数据分析算法实战-day12

文章目录 day12时序分解STL&#xff08;季节性趋势分解法&#xff09;奇异谱分析&#xff08;SSA&#xff09;经验模态分解&#xff08;EMD&#xff09; 时序分割ChangpointTreeSplitAutoplait有价值的辅助 时序再表征 day12 今天是第12天&#xff0c;昨天主要是针对信号处理算…

基于Python Scrapy的豆瓣Top250电影爬虫程序

Scrapy安装 Python实现一个简单的爬虫程序&#xff08;爬取图片&#xff09;_python简单扒图脚本-CSDN博客 创建爬虫项目 创建爬虫项目&#xff1a; scrapy startproject test_spider 创建爬虫程序文件&#xff1a; >cd test_spider\test_spider\spiders >scrapy g…

【Linux系统编程】:信号(2)——信号的产生

1.前言 我们会讲解五种信号产生的方式: 通过终端按键产生信号&#xff0c;比如键盘上的CtrlC。kill命令。本质上是调用kill()调用函数接口产生信号硬件异常产生信号软件条件产生信号 前两种在前一篇文章中做了介绍&#xff0c;本文介绍下面三种. 2. 调用函数产生信号 2.1 k…

腾讯云智能结构化OCR:以多模态大模型技术为核心,推动跨行业高效精准的文档处理与数据提取新时代

&#x1f3bc;个人主页&#xff1a;【Y小夜】 &#x1f60e;作者简介&#xff1a;一位双非学校的大三学生&#xff0c;编程爱好者&#xff0c; 专注于基础和实战分享&#xff0c;欢迎私信咨询&#xff01; &#x1f386;入门专栏&#xff1a;&#x1f387;【MySQL&#xff0…

内核执行时动态的vmlinux的反汇编解析方法及static_branch_likely机制

一、背景 在之前的博客里&#xff0c;我们讲到了tracepoint&#xff08;内核tracepoint的注册回调及添加的方法_tracepoint 自定义回调-CSDN博客&#xff09;和kprobe&#xff08;获取任意一个进程的共享内存的fd对应的资源&#xff0c;增加引用&#xff0c;实现数据的接管——…

Burp与其他安全工具联动及代理设置教程

Burp Suite 是一款功能强大的 Web 安全测试工具&#xff0c;其流量拦截和调试功能可以与其他安全工具&#xff08;如 Xray、Yakit、Goby 等&#xff09;实现联动&#xff0c;从而提升渗透测试的效率。本文将详细讲解 Burp 与其他工具联动的原理以及代理设置的操作方法&#xff…

Git配置公钥步骤

GIt公钥的配置去除了git push输入账号密码的过程&#xff0c;简化了push流程。 1.生成SSH公钥和私钥 ssh-keygen -t rsa -b 4096 -C “your_emailexample.com” 遇到的所有选项都按回车按默认处理。获得的公钥私钥路径如下&#xff1a; 公钥路径 : ~/.ssh/id_rsa.pub 私钥路径…

【蓝桥杯选拔赛真题96】Scratch风车旋转 第十五届蓝桥杯scratch图形化编程 少儿编程创意编程选拔赛真题解析

目录 scratch风车旋转 一、题目要求 编程实现 二、案例分析 1、角色分析 2、背景分析 3、前期准备 三、解题思路 1、思路分析 2、详细过程 四、程序编写 五、考点分析 六、推荐资料 1、入门基础 2、蓝桥杯比赛 3、考级资料 4、视频课程 5、python资料 scratc…

未来 AI 在企业应用中的重心

1. LLM 中精度、参数、数据、性能、以及成本之间的权衡是什么&#xff1f; 在大型语言模型&#xff08;LLM, Large Language Models&#xff09;中&#xff0c;精度、参数数量、训练数据量、性能和成本之间的权衡是一个复杂且多维度的问题。以下是这些因素之间关系的简要分析&…

Docker 安装 禅道-21.2版本-外部数据库模式

Docker 安装系列 1、拉取最新版本&#xff08;zentao 21.2&#xff09; [rootTseng ~]# docker pull hub.zentao.net/app/zentao Using default tag: latest latest: Pulling from app/zentao 55ab1b300d4b: Pull complete 6b5749e5ef1d: Pull complete bdccb03403c1: Pul…