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

计数排序(counting sort)

计算排序是一种通过计算每个元素出现的次数来进行排序的算法。它不比较元素,而是利用数组来“计数”,所以在某些情况下,它能比传统的比较排序快。

计数排序首先要找到要排序数组的最大值,然后创建一个统计数组存储每个排序元素的出现次数,然后累加计数数组,根据计数数组来确定每个元素的位置。

以一个实际例子来看,假设待排序数组:{2,8,7,6,4,5,2,8,5}

统计每个元素出现次数

要记录元素的统计次数,这里要创建一个统计数组用来记录次数,由于要记录每个元素的次数,所以要先找到元素的最大值来确定统计数组的容量,这里最大值是8,所以要创建一个 8+1长度的统计数组来存储元素记录数。考虑元素为0的情况。

最后统计数组结果如下:

002012112
下标012345678

这里统计数组下标待排序元素值,数组中值代表该元素出现次数

累加统计数组

这里累加就是将统计数组总的当前位置索引值改为前面所有统计数的和。

这一步其实就是确定每个元素的大致位置,只不过由于有相同的元素还需要进行微调。

这里从统计数组头开始具体看,其实可以理解成排名次,首先 0和1出现次数都是0直接舍弃,接着2出现了两次,前两名就是2个2,3

下标说明累加值
0次数是0,舍弃0
1次数是0,舍弃0
2次数是2,则这两个2(下标2)占据前两名2
3次数是0,舍弃2
4次数是1,一个4排第三名3
5次数2,两个5排占据4,5名5
6次数1,一个6排第6名6
7次数1,一个7排第7名7
8次数2,两个8占据8、9名9

确定元素位置

上面计数数组累加完成后,大致顺序已经出来了,只不过有相同元素存在导致元素具体位置存在空档和重复。

最后元素排序后的位置需要定义一个新的数组来存储,元素的位置还是

这一步就需要根据统计数组中的累加值来计算,计数数组中的累加值当对应位置元素被拿出一次后,当前位置累加数-1,便于下次在取的时候位置错开。

原数组 {2,8,7,6,4,5,2,8,5}

一次根据计数类加数确定位置

原数组元素计数数组累加值变化输出数组位置说明
22->12
89->89第一次拿出计数减去1
77->67
66->56
43->23
55->45
21->01第二次拿出在第一次基础上计算
88->78第二次拿出在第一次基础上计算
54->34第二次拿出在第一次基础上计算

最后确定每个元素在输出数组中的位置,排序也完成了。

代码实现

public static int[] sort(int[] arr){
	//1、找到数组最大值
	int max = arr[0];
	for (int i = 1; i < arr.length; i++) {
		if(arr[i] > max) max = arr[i];
	}

	//2、创建计数数组,数组长度 max+1,要存储所有可能元素计数,+1是考虑有元素0的情况
	int[] countArr = new int[max+1];
	//初始化
	for (int i = 0; i < countArr.length; i++) {
		countArr[i] = 0;
	}
	/**
	 * 元素计数,这里 countArr:下标是排序数组元素,值是当前这个数出现的次数
	 */
	for (int i = 0; i < arr.length; i++) {
		countArr[arr[i] ] += 1;
	}

	/**
	 * 累加计数 ,这里是将计数数组的值依次累加,这样就能知道每个元素(排序数组下标)对应的排序位置
	 */
	for (int i = 1; i < countArr.length; i++) {
		countArr[i] += countArr[i-1];
	}

	/**
	 * 构建输出数组
	 * 根据当前元素累加值确定输出数组位置,每次拿出一个,原来对应位置累加值-1
	 */
	int[] outArr = new int[arr.length];
	for (int i = 0; i < arr.length; i++) {
		outArr[ countArr[arr[i]]-1 ] = arr[i];
		countArr[arr[i]]--;
	}
	return outArr;
}

计数排序巧妙的运用了一个计数数组,每个元素值作为计数数组的下标来存取值。上面排序过程中也看到虽然没有进行排序比较,但是过程中创建了两个数组来存储计数和输出结果,空间复杂度提高。是一种用空间换时间的排序方式。

计算排序适合用于数组元素范围不大(例如 0 到 1000)。对于大量具有相同值的元素的排序。值的范围太大会造成计数数组空间偏大。如果排序中元素最小值较大,计数数组长度可以取为[最小值,最大值],元素下标统一偏移最小值即可。这样节省了最小值个数组长度空间。


http://www.kler.cn/news/325562.html

相关文章:

  • 计算机毕业设计 饮食营养管理信息系统的设计与实现 Java实战项目 附源码+文档+视频讲解
  • 问题:vscode 打印中文时终端输出乱码
  • 快手:数据库升级实践,实现PB级数据的高效管理|OceanBase案例
  • (22)activeMQ部署
  • Linux基础命令mkfs详解
  • C语言基础之数组
  • 低空经济时代:无人机飞行安全要点详解
  • 汽车线束之故障诊断方案-TDR测试
  • Leetcode 3302. Find the Lexicographically Smallest Valid Sequence
  • Anaconda虚拟环境默认路径在C盘怎么更改
  • 【bash】将本地未合入 master 的分支,生成对应 patche 文件
  • 计算机毕业设计 办公用品管理系统的设计与实现 Java实战项目 附源码+文档+视频讲解
  • JavaScript中的函数定义
  • 位图:如何实现网页爬虫中的 URL 去重功能?
  • 网络通信(学习笔记)
  • 【重学 MySQL】四十二、单行子查询
  • 城市大脑:智慧城市的神经中枢——典型实践与经验启示
  • K8s安装部署(v1.28)--超详细(cri-docker作为运行时)
  • Spring Boot 3.x 配置 Spring Doc以及导入postman带图详解
  • 数据集-目标检测系列-鼠检测数据集 mouse >> DataBall
  • 自动蛋鸡饲料机组:粉碎搅拌一步到位
  • 【高频SQL基础50题】11-15
  • Linux中的tr命令详解
  • 11-pg内核之锁管理器(六)死锁检测
  • PostgreSQL 一张表多个字段关联另一张表
  • 路由器的天线有什么用?数量多≠信号强?
  • C++番外篇-------排序算法总结
  • 数字孪生平台,助力制造设备迈入超感知与智控新时代!
  • 《C++多态性:开启实际项目高效编程之门》
  • Error:Decorators are not valid here. 使用Angular中的装饰器