当前位置: 首页 > news >正文

【数据结构入门】排序算法(5):计数排序

目录

1. 比较排序和非比较排序

2. 计数排序的原理

2.1 计数排序的弊端

3.代码复现

3.1 代码分析

3.2 排序核心

3.3 时间、空间复杂度


1. 比较排序和非比较排序

        比较排序是根据排序元素的具体数值比较来进行排序;非比较排序则相反,非比较排序例如:基数排序和计数排序,这两种排序方式虽然谐音类似,但是其实是完全不同的两种排序。

        首先基数排序是根据一个数字的某一位进行排序;而计数排序是根据某一个数字出现的次数来进行比较排序。

2. 计数排序的原理

①需要判断出整个原数组中最大的数字,例如是5,那么就需要创建一个0-5的数组(元素为6个)。

新创建的数组的下标表示该数字的值该数组的下标所对应的值就类似于该数字出现了几次

③遍历原始数组,如果遍历到某一个数字,那么新数组的对应位置的值就会+1;

④遍历完毕之后,对统计次数的数组进行排序即可;

排序的过程也非常巧妙,首先0下标的值是2,说明0出现了2次,1下标的值是0,说明没有1,2下标的值是2说明有两个2......我们直接对原数组进行覆盖即可。

2.1 计数排序的弊端

        例如需要将下面几个数进行计数排序,按照上面的原理,我们需要开辟一个0-5000(5001个数组元素)的数组,但是需要排序的数只有仅仅5个,这样一来,大量的数组空间会被浪费。

        从下图得知,最小的数是1000,也就是说0-1000这1000个数就没有必要为其准备空间了,所以只需要准备4000个空间就够了。

        此时数的存储是一个相对位置,例如1000存在数组下标为0的位置上,1005存在数组下标为5的位置上,1100存储在数组下标为100的位置上......5000存在数组下标为4000,计算方式a[i] - min,当前位置-最小值。

        所以说,比较稀疏的数进行排序的话,那么就会浪费大量连续空间。

3.代码复现

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>// 计数排序
void count_sort(int* arr, int size)
{// 选出最大值和最小值int max = arr[0];int min = arr[0];for (int i = 0; i < size; i++){if (arr[i] > max){max = arr[i];}if (arr[i] < min){min = arr[i];}}// 创建一个具体数量的数组int range = max - min + 1;// 0-9一共10个数int* countArr = (int*)malloc(sizeof(int) * range);memset(countArr, 0, range * sizeof(int));// 遍历原数组给countArr赋值,计数for (int i = 0; i < size; i++)// countArr下标是arr的值;其值是次数{int val = arr[i] - min; // 这里是相对位置,若只有0-4000个位置,1005就是5号位置,// 这里要arr[i] - min得到相对位置++countArr[val];}int index = 0;// 原数组的覆盖下标// 遍历countArr将原数组覆盖for (int j = 0; j < range; j++){// 计数数组的值是几就覆盖几次while (countArr[j]--){arr[index++] = j + min; // 将下标进行还原,之前是-min存入countArr的 }}free(countArr);
}int main()
{int a[] = { 3,5,4,1,7,9,8,5,0,5 };int size = sizeof(a) / sizeof(int);count_sort(a, size);for (int i = 0; i < size; i++){printf("%d ", a[i]);}return 0;
}

3.1 代码分析

①首先计算出原数组的最大最小值,最大值-最小值+1就是计数数组的长度。

②遍历原数组,原数组的值对应计数数组的下标,如果遍历到2,那么就是计数数组下标为2的值进行+1;

③遍历计数数组,将对应下标作为原数组的值,计数数组的值就是需要赋值的次数,例如上图的5,在计数数组中存储的方式是index = 5,val = 3,那么就是将5赋值原数组,赋值3次,结果如下图。

3.2 排序核心

        就是利用数组的下标将无序的数字分别放入对应的下标,从而实现有序,这里对于重复数字进行一个累加的过程,反作用于原数组就是赋值的次数,这样的排序类似于下图:

        利用连续的有序数组下标作为“柱子”,如果该数字为这个柱子的编号,那么这个柱子就套一个圈,每一个柱子套圈的个数其实就是该数字出现的次数,由于柱子的编号是连续且有序,其实在套圈的过程中,我们已经将数字排好序了,此时只需要将结果覆盖原数组即可。

        所以这个算法可以运用于,数据非常集中,有大量重复出现的数字的数组中。

3.3 时间、空间复杂度

        我们注意这里的时间复杂度,看代码我们可以发现遍历了一次原数组,这里时间复杂度是O(n),后面需要遍历计数数组,那么时间复杂度是O(range),那么最后的时间复杂度就是:

O(n + range)

空间复杂度,这里只需要一个range大的数组,所以这里是:

O(range)

(不是橘子哈)


文章转载自:

http://EH8137dZ.mzcrs.cn
http://UhoLvlHM.mzcrs.cn
http://mblxxmpg.mzcrs.cn
http://tfPyTiVc.mzcrs.cn
http://3VY2CPGs.mzcrs.cn
http://GV7VVOqE.mzcrs.cn
http://iG4Q3Lue.mzcrs.cn
http://LxmezNNp.mzcrs.cn
http://avFyZTf5.mzcrs.cn
http://lJ0nTNeV.mzcrs.cn
http://PBurlsP1.mzcrs.cn
http://rWSRNolN.mzcrs.cn
http://ZljQu4x3.mzcrs.cn
http://1d2DiwGk.mzcrs.cn
http://LI6pzHYx.mzcrs.cn
http://pcTODcMn.mzcrs.cn
http://y9bLLYot.mzcrs.cn
http://oRLUu6Ts.mzcrs.cn
http://ShaUir6R.mzcrs.cn
http://sahMvwE2.mzcrs.cn
http://v300b617.mzcrs.cn
http://EgH0oH0g.mzcrs.cn
http://HRNENXMw.mzcrs.cn
http://8WyrqlOo.mzcrs.cn
http://2gCfHppq.mzcrs.cn
http://cT0FPUTg.mzcrs.cn
http://El8t1kNT.mzcrs.cn
http://Dya8KZBh.mzcrs.cn
http://1t9oBgr2.mzcrs.cn
http://K8zM3fWp.mzcrs.cn
http://www.dtcms.com/a/385143.html

相关文章:

  • 超大规模多模态交通数据集:320TB+海量数据资源,涵盖行车视频、无人机航拍、第一视角步行骑行与道路监控,助力自动驾驶与智慧交通算法突破
  • [数据结构——Lesson13.冒泡与选择排序]
  • tar-符号连接(软连接)
  • php学习 (第六天)
  • MTK Linux Charger驱动分析(二) - power_supply_core.c
  • 如何做好AI智能体
  • 邻接矩阵幂 A^m 的几何意义
  • PL3381T/PL3383T/PL3384T 12V非隔离降压型芯片(200/300/400mA)
  • 食品科技企业NotCo完成SAP系统升级 构建统一数字化平台
  • LinuxC++项目开发日志——高并发内存池(6-内存回收机制)
  • 数值计算2
  • 硬件 - oring多电源切换
  • RocketMQ-高性能消息中间件的原理
  • DevOps历程--GitLab安装与使用教程(Docker安装和编译安装两种方式)
  • 大屏可视化动图渲染
  • Claude Code生态、实战
  • 系统架构设计师备考第24天——需求工程
  • 逻辑回归模型:基于鸢尾花数据集的多分类任务全流程
  • 实战适配器模式
  • OpenLayers数据源集成 -- 章节十三:EsriJSON图层详解
  • RabbitMQ—运维篇
  • 一站式YOLO目标检测解决方案:训练、测试、推理与数据集转换全流程指南
  • lamp脚本部署
  • 前端构建工具有哪些?常用前端构建工具对比、前端构建工具推荐与最佳实践分析
  • Charles日志分析与流量监控技巧 高效排查接口与性能问题
  • ACM模式的输入部分——input().strip() 与 sys.stdin.readline() 的不同
  • ““.equals(studentID)
  • 【Lesson 3】CUDA 编程模型:线程、块、网格 —— Ubuntu 22.04 + RTX 30/40 系列实战
  • [Windows]C盘瘦身 --- 软件搬家
  • CLIP 完全上手指南:从安装、下载加速、文本/图像编码到图文匹配,一篇全搞定!