🥳前端算法面试之桶排序-每日一练

前言

桶排序是将原来的 n 条数据分成 m 份。每一份看成是一个桶。桶之间是有序的,只要桶内排好序,就可以按照桶的顺序依次取出每个数据。这样取出来的数据就是有序的了

举个例子,现在有一万份订单,订单的金额在 1 元到 1 万元之间。现在需要对订单的金额排序,由低到高,请问如何才能在 logn 的复杂下实现呢

利用桶排序的话,可以将一万份订单,分成 100 份,第一份的金额区间是 0-100 元,第二份的金额区间是 100-200 元,依次类推,第一百份的金额在 9900-10000 之间

然后将桶内的数据通过快速排序的方法排好序。读取数据的时候,就可以从前往后读,这样的数据,就是天然有序的了。这样分需要额外的空间存储的支持,但是分的越细,桶排序的速度越快。

想象一下,我们吧一万份订单直接分成一万份,也就是一万个桶,每个桶内部所存储的金额是相同,然后每个桶之间所存储的金额差是一元。这样所有订单的金额都有了对应的桶了。现在只要把所有订单全部遍历一遍,将订单放到对应金额的桶里面。不就完成了订单的排序吗?

对的,只要遍历一遍订单,就能排好序,那桶排序的复杂度不就是 O( n ) 么?

下面做一个定量分析

复杂度分析

  1. k = n/m,n 条数据,一共分成 m 份,每份有 k 条数据。
  2. 每个桶的内部使用快速排序的算法,时间复杂度就是k * logk。而且有 m 个桶,整体复杂度就是 m * k * logk,即 nlog(n/m)
  3. 当桶分的越多,log(n/m)就越小,整体的复杂度也就越接近 n

这就是桶排序时间复杂度接近于n 的证明了

代码实现

用代码实现桶,首先想到的就是散列表,不过散列函数不再是取余,而是散列函数的值等于自变量本身,即 key = hash(key). 解决冲突的方式是链表,也即用链表的物理存储方式来表示一个桶

下面看代码:

javascript 复制代码
const _tongSort = (array, hashArray) => {
	for (let i = 0; i < array.length; i++) {
		const hashIndex = array[i];
		const temp = { value: hashIndex, next: null };
		if (!hashArray[hashIndex]) {
			hashArray[hashIndex] = temp;
		} else {
			temp.next = hashArray[hashIndex];
			hashArray[hashIndex] = temp;
		}
	}
	return hashArray;
};

const tongSort = (array, maxValue) => {
	const hashArray = Array(maxValue + 1).fill(null);
	return _tongSort(array, hashArray);
};

这段代码定义了两个函数:_tongSort 和 tongSort。

_tongSort 函数用于实现桶排序算法, 它的输入参数是一个数组 array 和一个哈希数组 hashArray。函数的实现方式是遍历数组中的每个元素, 将这个元素放到对应的桶中,这里的桶是用链表的方式表示的。桶没有初始化,就创建一个桶,如果已经有了桶,并且桶中已经有了其他的元素,就使用头插法插链表中。

tongSort 函数是同排序算法的入口函数,它的输入参数是一个数组 array 和一个最大值 maxValue。函数的实现方式是创建一个长度为 maxValue + 1 的哈希数组 hashArray,然后将 _tongSort 函数的返回值作为 hashArray 的值。最后返回 hashArray。

桶排序比较特殊,他需要预先知道所排序元素的最大值,这样才能生成对应的 hashArray。这在实际排序场景是没有问题的。并且所排序的元素对象的值不能太大,否则不能使用。桶排序仅支持正整数,小数也不能支持。不过对于不满足条件的数,可以做些处理,比如小数可以放大变成整数,负数可以用移码的策略变成正数等

正是因为桶排序的限制如此的多,所以语言排序 API 的底层实现通常是快速排序,或者是归并排序

测试代码:

javascript 复制代码
const data = [32, 45, 12, 34, 35, 42, 324, 123, 21, 23];

const sortedArray = tongSort(data, 324);

const printSortedArray = (hashArray) => {
	for (let i = 0; i < hashArray.length; i++) {
		if (hashArray[i]) {
			let temp = hashArray[i];
			while (temp) {
				console.log(temp.value);
				temp = temp.next;
			}
		}
	}
};

printSortedArray(sortedArray);
// 12
// 21
// 23
// 32
// 34
// 35
// 42
// 45
// 123
// 324

在调用sortedArray之后,得到了一个 hashArray,这个数组还不能直接使用,需要一个辅助函数。上面代码中使用了打印的辅助函数printSortedArray。可以看到打印结果是没有问题的。

想了解更多关于 hash 列表的内容,可以看这篇文章:🥳每日一练-删除数组中重复的元素-JS简易版

总结

这篇文章分享了桶排序,桶排序的实现,复杂度分析,以及使用场景,使用限制等等,如果用hash表来实现的话,桶排序是不是叫hash排序更合适呢哈哈

有什么问题可以评论区留言哦。我每天都会分享一篇算法小练习,喜欢就点个赞+关个注吧

相关推荐
Pniubi28 分钟前
力扣438.找到字符串中所有字母异位词
算法·leetcode·职场和发展
usdoc文档预览44 分钟前
USDOC系列之PPT文件在线编辑-VUE前端实现在线浏览器在线编辑PPT文档
前端·vue.js·编辑器·office365·ppt在线编辑·office文件在线编辑·文件在线编辑
用户2705077725241 小时前
Agent 调工具卡住?3 种超时与取消策略实测对比
前端
yeccheng1 小时前
MySQL 索引超详解:从底层 B+ 树到面试高频考点
java·开发语言·jvm·mysql·面试
LuHang2 小时前
我一行代码没写,把领导派的活做成了公司内部系统😭
前端
明月_清风2 小时前
Meta 开源了一个 AI Native 组件库:Astryx,150+ React 组件,专为 AI Agent 而设计
前端·人工智能·ai编程
用户850869276152 小时前
秒杀系统中 Shell 脚本并发控制 Bug:究竟哪里出了
前端
東隅已逝,桑榆非晚3 小时前
算法6. 双指针法-查找总价格为目标的两个商品
c++·学习·算法
Eyfcom3 小时前
〖物联网终端实战 01〗UWB 室内高精度定位:仓储 AGV 与人员的厘米级轨迹追踪
物联网·算法·物流系统·快递系统·跨境物流快递系统·物联网终端实战
bro_Java6664 小时前
《排序的底层逻辑:比较、交换与分治》
java·算法·排序算法