数据结构与算法之排序: 计数排序 (Javascript版)

news/2024/7/24 2:53:33 标签: 算法, 排序, 计数排序

排序

  • 排序:把某个乱序的数组变成升序或降序的数组 (这里用数组来做举例)

计数排序

  • 核心思想:通过计数而非比较来进行排序,借助数组下标本身就是有序的原理实现
  • 适用范围:较小的非负整数序列和最小值和最大值之间的数字范围比较合适
  • 基数排序需要新增一个计数数组(待累计数组)
    • 计数数组:即新的临时的初始化数组用于计数,需要找到原始数组中最大的值,再加1,才是这个数组的长度,存储 [0 ~ max]
    • 累计数组:是由计数数组计算后得到的,下标是原数组的值,元素值是累计的个数,即重复的个数

算法实现

1 )基础版本

function countSort(list) {
	const len = list.length;
	if (len < 2) return;
	// 获取最大值
	const max = Math.max.apply(null, list);
	// 初始化计数数组
	const countList = new Array(max + 1).fill(0); // 数组大小,存放[0~max]
	// 对原数组的数据在计数数组中累计,原数组的值是计数数组的下标
	let i;
	for(i = 0; i < len; i++) countList[list[i]]++; // 遍历完成后计数数组就变成了累计数组
	// 基于累计数组生成排好序的数组,这里利用了下标即是有序的原理
	i = 0; // 重新使用i
	for(let j = 0; j < max + 1; j++) {
    	// 内层循环不会到n, 一般是常数级别的,但是这样写似乎也不是太好,嵌套会增加时间复杂度
		for (let k = 0; k < countList[j]; k++) list[i++] = j; // 这里j就是下标,其实就是原数组的值
	}
}

const list = [2,3,8,7,1,2,2,2,7,3,9,8,2,1,4,2,4,6,9,2];
countSort(list);
console.log(list); // [1, 1, 2, 2, 2, 2, 2, 2, 2, 3, 3, 4, 4, 6, 7, 7, 8, 8, 9, 9]

2 )优化版本:优化时间复杂度(空间换时间)

function countSort(list) {
	const len = list.length;
	if (len < 2) return;
	// 获取最大值和最小值
	const max = Math.max.apply(null, list);
	const min = Math.min.apply(null, list);
	// 初始化计数数组
	const countList = new Array(max - min + 1).fill(0);
	// 对原数组的数据在计数数组中累计,原数组的值是计数数组的下标
	let i;
	for(i = 0; i < len; i++) countList[list[i] - min]++; // 遍历完成后计数数组就变成了累计数组
	// 基于累计数组生成排好序的数组,这里利用了下标即是有序的原理
	let result = [];
	i = 0; // 重新使用i
	for(let j = 0; j < max + 1; j++) {
		if (!countList[j]) continue;
		countList[j] > 1 ? (result = result.concat(new Array(countList[j]).fill(j))) : result.push(j);
	}
	return result; // 替换
}

const list = [102,103,108,107,101,102,102,102,107,103,109,108,102,101,104,102,104,106,109,102];
const result = countSort(list);
console.log(result); // 101,101,102,102,102,102,102,102,102,103,103,104,104,106,107,107,108,108,109,109

3 )优化版本:优化时间复杂度(空间换时间) + 优化存储空间

function countSort(list) {
	const len = list.length;
	if (len < 2) return;
	// 获取最大值和最小值
	const max = Math.max.apply(null, list);
	const min = Math.min.apply(null, list);
	// 初始化计数数组
	const countList = new Array(max - min + 1).fill(0);
	// 对原数组的数据在计数数组中累计,原数组的值是计数数组的下标
	let i;
	for(i = 0; i < len; i++) countList[list[i] - min]++; // 遍历完成后计数数组就变成了累计数组
	// 基于累计数组生成排好序的数组,这里利用了下标即是有序的原理
	i = 0; // 重新使用i
	let result = [];
	for(let j = 0; j < max - min + 1; j++) {
		if (!countList[j]) continue;
		countList[j] > 1 ? (result = result.concat(new Array(countList[j]).fill(j + min))) : result.push(j + min);
	}
	return result;
}

const list = [102,103,108,107,101,102,102,102,107,103,109,108,102,101,104,102,104,106,109,102];
const result = countSort(list);
console.log(result); // 101,101,102,102,102,102,102,102,102,103,103,104,104,106,107,107,108,108,109,109

总结

  • 计数排序的适用范围有限:最优版时间复杂度可降低到 O(n), 是最快的排序算法, 但是有两个前提需要满足
    • 1)需要排序的元素必须是非负整数(下标不能是负数和小数)
    • 2)排序元素的取值要在一定范围内,并且比较集中
  • 满足以上两个条件,才能最大发挥出计数排序的优势, 否则不适用
  • 计数排序的缺点
    • 基础版空间浪费,优化版解决了这个问题
    • 将数组长度定为 max-min+1, 即不仅要找出最大值,还要找出最小值
  • 缺点弥补:根据两者的差来确定计数数组的长度则可弥补之
  • 计数排序是非常稳定的排序算法,但是适用场景确实有限

http://www.niftyadmin.cn/n/5142422.html

相关文章

栈及其栈的模拟实现和使用

1. 栈(Stack) 1.1 概念 栈 &#xff1a;一种特殊的线性表&#xff0c;其 只允许在固定的一端进行插入和删除元素操作 。进行数据插入和删除操作的一端称为栈顶&#xff0c;另一端称为栈底。栈中的数据元素遵守后进先出LIFO &#xff08; Last In First Out &#xff09;的原则…

58同城面试

一、Java八股 1、ThreadLocal的底层原理是什么&#xff1f; ThreadLocal 在Java中用于提供线程局部变量&#xff0c;这些变量在每个线程中都有独立的副本&#xff0c;互不干扰。其底层原理可以简要描述如下&#xff1a; 数据存储: 每个线程中都有一个 ThreadLocalMap 的实例&…

Ubuntu20.04安装CUDA、cuDNN、tensorflow2可行流程(症状:tensorflow2在RTX3090上运行卡住)

最近发现我之前在2080ti上运行好好的代码&#xff0c;结果在3090上运行会卡住很久&#xff0c;而且模型预测结果完全乱掉&#xff0c;于是被迫研究了一天怎么在Ubuntu20.04安装CUDA、cuDNN、tensorflow2。 1.安装CUDA&#xff08;包括CUDA驱动和CUDA toolkit&#xff0c;注意此…

国际多语言出海商城源码/返佣产品自动匹配拼单商城源码

源码介绍&#xff1a; 国际多语言出海商城返佣产品自动匹配订单拼单商城源码&#xff0c;8国多语言出海拼单商城。此网站是很多巴西客户定制的原型&#xff0c;已投放运营符合当地本地化。 多语言商城返利返佣投资理财派单自带余额宝&#xff0c;采取全新支付端口&#xff0c…

XUbuntu22.04之simplenote支持的Markdown语法总结(一百九十一)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 人生格言&#xff1a; 人生…

车载网络测试 - UDS诊断篇 - CAN与OSI七层模型

目录 为什么会介绍OSI七层模型&#xff1f; CAN规范与OSI模型 1、Physical Layer 1 2、Data Link Layer 2 3、Network Layer 3 & Transport Protocol Layer 4 4、Transport Protocol Layer 4 5、Session Layer 5 & Presentation Layer 6 & Application Laye…

干洗店服务预约小程序有什么作用

要说干洗店&#xff0c;近些年的需求度非常高&#xff0c;一方面是人们生活品质提升&#xff0c;另一方面则是各种服饰对洗涤要求提升等&#xff0c;很多人的衣服很多也会通过干洗店进行清洁。 而对从业商家来说&#xff0c;市场庞大一方面需要不断进行市场教育、品牌提升&…

Express框架开发接口之书城商店原型图

这是利用Axure画的&#xff0c;简单画一下原型图&#xff0c;根据他们的业务逻辑我们完成书城商店API开发 首页 分类 购物车 个人中心