【数据结构初阶】--排序(五)--计数排序,排序算法复杂度对比和稳定性分析

🔥个人主页:@草莓熊Lotso

🎬作者简介:C++研发方向学习者

📖个人专栏: 《C语言》 《数据结构与算法》《C语言刷题集》《Leetcode刷题指南》

⭐️人生格言:生活是默默的坚持,毅力是永久的享受。

前言:今天这篇文章主要是想给大家分享一下计数排序,并且对前面实现过的排序算法的时间复杂度,空间复杂度,稳定性进行一个归纳总结。话不多说,我们直接进入正文内容。


目录

一.计数排序

核心步骤:

代码实现:

计数排序的特性: 

 二.排序算法复杂度及稳定性分析

各排序算法对比表: 


一.计数排序

计数排序(Counting Sort)又称为鸽巢原理,是一种非比较型的线性时间排序算法,适用于 输入数据范围明确且较窄的场景。核心思想是通过“统计每个值的出现次数”,直接确定元素的最终位置,跳过耗时的比较操作。


核心步骤:

1. 确定数据范围
遍历数组,找到最大值 max 和最小值 min,计算数据范围 range = max - min + 1。
(目的:创建合适大小的计数数组,避免空间浪费)

2. 统计元素出现次数
创建计数数组 count(长度为 range),注意count数组的初始化(开辟时用calloc或者后续用memset),遍历原数组,将每个元素 arr[i] 映射到 count[arr[i] - min](减去 min 是为了处理包含负数的情况,一定要用arr[i]-min),统计每个值的出现次数。

3. 将count数组中的数据排序还原到原数组中

定义一个索引变量index,用于记录原数组arr中即将写入数据的位置。遍历count数组(从0开始,然后小于<range),根据count[i]统计到的个数进行循环,循环次数等于该值出现的次数,将数组的原始数据值放入arr原始数组中(对应原始值一定是i+min)


代码实现:

//非比较排序--计数排序
void CountSort(int* arr, int n)
{//找最大最小值确定范围int min = arr[0]; int max = arr[0];for (int i = 0; i < n; i++){if (arr[i] < min){min = arr[i];}if (arr[i] > max){max = arr[i];}}int range = max - min + 1;int* count = (int*)malloc(sizeof(int) * range);if (count == NULL){perror("malloc fail!");exit(-1);}//对count初始化,可以用memset也可以前面申请空间的时候使用callocmemset(count, 0, sizeof(int) * range);//统计次数,映射,下标为arr[i]-minfor (int i = 0; i < n; i++){count[arr[i] - min]++;}//排序int index = 0;//用range就可以了for (int i = 0; i < range; i++){while (count[i]--){arr[index++] = i + min;//这里需要用i+min}}
}

test.c:

#include"Sort.h"void PrintArr(int* arr, int n)
{for (int i = 0; i < n; i++){printf("%d ", arr[i]);}printf("\n");
}void test1()
{int a[] = { 5, 3, 9, 6, 2, 4, 7, 1, 8 };int size = sizeof(a) / sizeof(a[0]);printf("排序前:");PrintArr(a, size);//直接插入排序//InsertSort(a, size);//希尔排序//ShellSort(a, size);//直接选择排序//SelectSort(a, size);//堆排序//HeapSort(a, size);//冒泡排序//BubbleSort(a, size);//快速排序//QuickSort(a, 0, size - 1);//非递归快速排序//QuickSortNoare(a, 0, size - 1);//快速排序进阶版//QuickSortMore(a, 0, size - 1);//归并排序//MergeSort(a, size);//非递归实现归并排序//MergeSortNore(a, size);//非比较排序--计数排序CountSort(a, size);printf("排序后:");PrintArr(a, size);
}int main()
{test1();return 0;
}

--测试完成,打印没有问题,升序排序正确,退出码为0 

计数排序的特性: 

  • 计数排序在数据范围集中时,效率很高,但是适用范围以及场景有限。
  • 时间复杂度:O(n+range)
  • 空间复杂度:O(range)
  • 稳定性:稳定

 二.排序算法复杂度及稳定性分析

稳定性:假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序,这些记录的相对次序保持不变,即在原序列中,r[i]=r[j],且r[i]在r[j]之前,而在排序后的序列中,r[i]仍在r[j]之前,则称这种排序算法是稳定的;否则称为不稳定的。

各排序算法对比表: 

--其中冒泡排序,直接插入排序,归并排序是稳定的,这里就不过多介绍了,我们主要通过一些特例来看下那些不稳定的排序算法。至于时间复杂度和空间复杂度,博主大部分都在前面的博客中分享过了。

1.直接选择排序:

2.希尔排序:

3.堆排序:

4.快速排序:

--前面一直没给大家展示过Sort.h文件,在这里给大家看一看

#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<string.h>//插入排序
//1)直接插入排序
void InsertSort(int* arr, int n);
//2)希尔排序
void ShellSort(int* arr, int n);//选择排序
//1)直接选择排序
void SelectSort(int* arr, int n);
//2)堆排序
void HeapSort(int* arr, int n);//交换排序
//1)冒泡排序
void BubbleSort(int* arr, int n);
//2)快速排序
void QuickSort(int* arr, int left, int right);
//快速排序非递归版本
void QuickSortNoare(int* arr, int left, int right);
//快速排序进阶版本
void QuickSortMore(int* arr, int left, int right);//归并排序--主函数里面不递归,所以可以先不传left和right
void MergeSort(int* arr, int n);
//非递归实现归并排序
void MergeSortNore(int* arr, int n);//非比较排序--计数排序
void CountSort(int* arr, int n);

往期回顾:

【数据结构初阶】--排序(一):直接插入排序,希尔排序

【数据结构初阶】--排序(二)--直接选择排序,堆排序

【数据结构初阶】--排序(三):冒泡排序,快速排序

【数据结构初阶】--排序(四):归并排序

结语:本篇博客就到此结束了,后续应该还会更新一篇归并排序的进阶,然后就正式进入C++的学习了。我们数据结构初阶讲这些数据结构都是用C语言实现的,还有些比较难的数据结构在后续C++的学习中我们也会接触到,但是利用C++来实现就方便很多了,如果文章对你有帮助的话,欢迎评论,点赞,收藏加关注,感谢大家的支持。

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

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

相关文章

InfluxDB 数据备份与恢复高级策略(二)

案例实战&#xff1a;InfluxDB 数据备份恢复业务场景描述假设我们正在参与一个大型的物联网项目&#xff0c;该项目涉及分布在不同区域的数千个传感器设备 &#xff0c;这些设备实时采集环境温度、湿度、设备运行状态等数据&#xff0c;并将这些数据存储在 InfluxDB 数据库中。…

sqli-labs通关笔记-第36关GET宽字符注入(单引号闭合 手工注入+脚本注入 3种方法)

目录 一、转义函数 1、mysqli_real_escape_string 2、addslashes 3、转义区别 二、宽字符注入 三、sqlmap之tamper 四、sqlmap之unmagicquotes 五、源码分析 1、代码审计 2、SQL注入安全性分析 六、渗透实战 1、进入靶场 2、id1探测 3、id-1探测 4、id1%df and…

手撕设计模式——咖啡点单系统之装饰模式

手撕设计模式——咖啡点单系统之装饰模式 1.业务需求 ​ 大家好&#xff0c;我是菠菜啊&#xff0c;好久不见&#xff0c;今天给大家带来的是——装饰模式。老规矩&#xff0c;在介绍这期内容前&#xff0c;我们先来看看这样的需求&#xff1a;现在有一个咖啡馆&#xff0c;有…

LRU Cache缓存替换算法

目录 一、LRU 是什么&#xff1f;Cache是什么&#xff1f; 二、LRU Cache的实现 三、源码 一、LRU 是什么&#xff1f;Cache是什么&#xff1f; LRU 是 "Least Recently Used" 的缩写&#xff0c;意思是“最近最少使用”。它是一种常用的 缓存&#xff08;Cache&…

自定义视图:图形与图像的处理(二):绘图

除了使用已有的图片之外&#xff0c;Android应用还常常需要在运行时动态地生成图片&#xff0c;比如一个手机游戏&#xff0c;游戏界面看上去丰富多彩&#xff0c;而且可以随着用户动作而动态改变&#xff0c;这就需要借助于Android的绘图支持了。1. Android绘图基础:Canvas、P…

微服务、服务网格、Nacos架构与原理

Nacos架构与原理 -服务网格生态-阿里云开发者社区 ------ 该文章用于学习参考,如有侵权,请直接联系下架 服务网格的核心职责:治理“服务通信” 包括但不限于: 功能 举例说明 负载均衡 动态选择服务实例 熔断、重试 某个服务失败时自动切换、重试 流量路由 灰度发布、蓝绿…

STM32——启动过程浅析

总&#xff1a;STM32——学习总纲 参考文件&#xff1a; STM32 MAP文件浅析-V1.1 STM32 启动文件浅析_V1.2 Cortex-M3权威指南(中文)、ARM Cotrex-M3权威指南(英文).zip 一、Map文件解析 1.1 MDK编译过程文件 在编译中&#xff0c;会生成11种编译过程文件&#xff0c;可…

区块链简介

一、区块链简介 狭义上的定义&#xff1a; 区块链是一种链式数据结构&#xff0c;通过按时间顺序将数据块逐一连接形成。这种结构通过密码学确保了数据的不可篡改性和不可伪造性&#xff0c;形成了一种分布式账本技术。 广义上的定义&#xff1a; 区块链技术不仅仅是一种数据…

NestJS中@Injectable装饰器

一、基础定义与核心作用 1.1 什么是Injectable&#xff1f; Injectable() 是 NestJS 依赖注入&#xff08;Dependency Injection, DI&#xff09;系统的核心装饰器&#xff0c;用于将类标记为可注入的提供者&#xff08;Provider&#xff09;。它告知 NestJS 的 IoC&#xff08…

【机器学习深度学习】大模型应用落地:微调与RAG的角色与实践

目录 前言 一、微调与RAG&#xff1a;大模型应用落地的两大支柱 1. 微调&#xff08;Fine-tuning&#xff09; 2. RAG&#xff08;Retrieval-Augmented Generation&#xff09; 二、微调可以做什么&#xff1f; 1. 模型自我认知调整 2. 对话风格优化 3. 提升问题理解能…

List、ArrayList 与顺序表

目录 一、List 介绍 二、线性表 三、自己实现 ArrayList 3.1 显示元素 3.2 增 3.2.1 默认在数组后面新增元素 3.2.2 在指定位置中新增元素 3.3 查 3.4 取值 3.5 改 3.5.1 把 pos 位置的元素修改成 value 3.5.2 删除某个元素 3.5.3 清空 四、认识 ArrayList 4.0 说…

Baumer工业相机堡盟工业相机如何通过YoloV8深度学习模型实现各类垃圾的分类检测识别(C#代码UI界面版)

Baumer工业相机堡盟工业相机如何通过YoloV8深度学习模型实现各类垃圾的分类检测识别&#xff08;C#代码UI界面版&#xff09;工业相机使用YoloV8模型实现各类垃圾的分类检测识别工业相机通过YoloV8模型实现各类垃圾的分类检测识别的技术背景在相机SDK中获取图像转换图像的代码分…

EasyExcel高效工具类:简化Excel导入导出,支持多Sheet与枚举转换

文章目录前言一、依赖坐标二、工具类&#xff1a;ExcelUtil三、测试1.实体类2.前置操作3.单Sheet导出4.单Sheet导入5.多Sheet导出6.多Sheet导入7.完整代码四、扩展&#xff1a;自定义注解实现枚举类型转换1.枚举接口2.枚举类3.注解4.转换类5.使用示例6.测试总结前言 在现代应用…

技术速递|GitHub Copilot for Eclipse 迈出重要一步

我们非常高兴地宣布&#xff1a;2025 年 7 月 22 日&#xff0c;GitHub Copilot for Eclipse 又迈出了重要一步&#xff0c;Eclipse 变得更智能、更快捷&#xff0c;而且与 Eclipse 的集成也更无缝了&#xff01;这是继新功能上线以来&#xff0c;又一次质的提升。 &#x1f…

Coze Loop:开源智能体自动化流程编排平台原理与实践

项目简介 Coze Loop 是 Coze 团队开源的智能体自动化流程编排平台。它以“Loop”为核心概念,支持开发者通过低代码/可视化方式,将多种 AI Agent、插件、API、数据流等灵活编排为自动化工作流,实现复杂的智能体协作、任务自动化和多模态数据处理。Coze Loop 适用于企业自动化…

[GESP202309 四级] 2023年9月GESP C++四级上机题题解,附带讲解视频!

本文为2023年9月GESP C四级的上机题目的详细题解&#xff01;觉得写的不错或者有帮助可以点个赞啦。 目录 题目一讲解视频: 题目二讲解视频: 题目一:进制转换 解题思路: 代码(C): 题目二:变长编码 解题思路: 代码(C): 题目一讲解视频: 2023年9月GESP C四级上机题一题目…

【AI编程工具IDE/CLI/插件专栏】-国外IDE与Cursor能力对比

AI编程专栏(二) - Cursor 深度使用指南 Cursor 深度使用指南(二) - 新能力使用教程 从Trae 2.0与CodeBuddy IDE发布&#xff0c;谈大厂布局IDE 如何选择AI IDE&#xff1f;对比Cursor分析功能差异 AI编程工具IDE/CLI/插件专栏-热门AI编程CLI初识与IDE对 前面文章介绍过了国…

word2vector细致分解(CBOW, SKIP_GRAM, 层次soft Max, 负采样)

1 前世今生&#xff1a;NGRAM NGRAM&#xff1a;将词当成一个离散的单元&#xff08;因此存在一定的局限性&#xff0c;没有考虑到词与词之间的关系&#xff09; neural network language model&#xff1a;只能处理定长序列&#xff0c;训练慢。使用RNN之后有所改善 2 两种训…

Elasticsearch向量库

在Elasticsearch&#xff08;ES&#xff09;最新版本&#xff08;目前8.x系列&#xff09;中&#xff0c;无需额外的“embedding插件”&#xff0c;因为ES从7.14版本开始就原生支持向量数据类型&#xff08;dense_vector&#xff09; 和向量搜索能力&#xff0c;可直接作为向量…

嵌入式学习的第四十四天-ARM

一、ARM内核基础知识1.ALU算术逻辑单元&#xff1b;完成运算的电路2.通用寄存器&#xff1a;R0~R15R13&#xff08;SP&#xff09;&#xff1a;栈指针寄存器&#xff1a;指向栈的指针&#xff08;指向正确的位置&#xff09;&#xff0c;为了保护现场 R14&#xff08;LR…