「这是我参与2022首次更文挑战的第20天,活动详情查看:2022首次更文挑战」
基数排序
介绍
基数排序 它是 计数排序 算法的进阶,当然它也是基于 桶 的思想,来进行的排序算法。
基数排序 是通过每次 对比 相同位数的值,来进行分组。
分组后的数据需要放到下标为 0~9 不同的桶中,因为数据需要 先入先出,后入后出 的特性,所以这里使用 队列 这种数据结构的特性来进行保存。关于队列的讲解,这篇 数据结构-队列 有详细介绍。
直到最后位数所在值超过了 数据里面 最大的值即结束。
- 动图演示
详解
-
获取最大值
善于用js的 ES6 语法很快
const max = Math.max(...arr) -
定义一个桶的数组,里面是10个桶(队列)
这里有个知识点,可以用 数组的 Array.from 来进行创建,它的 MDN 中有关于在
Array.from中使用箭头函数 ,它的详细介绍,可以看下。-
用法如下
Array.from({ length: 5 }, (item, index) => { console.log('item: ', item) console.log('index: ', index) }) -
创建的代码
const buckets = Array.from({ length: 10 }, () => new Queue())
-
-
创建位数,循环比较
创建一个从 个位数 开始的值,每次循环后将位数 digit * 10 的操作,直到 这个值 大于 最大值结束。
let digit = 1 while (digit <= max){} -
队列
关于队列的知识,可以查看 数据结构-队列 的讲解
基数排序 中,也主要获取到数据项里每个值的 位数 后,进行 入队 和 出队 操作,出队操作时,会判断 队列 中 是否为空 的操作,依次出队,直到队列为空。
完整代码
class Queue {
constructor() {
this.arr = []
}
enqueue(element) {
this.arr.push(element)
}
dequeue() {
return this.arr.shift()
}
front() {
if (this.isEmpty()) return null
return this.arr[0]
}
isEmpty() {
return this.arr.length === 0
}
size() {
return this.arr.length
}
find(index) {
return this.arr[index]
}
clear() {
this.arr = []
}
}
/**
* num 代表 当前数字, digit 代表位数 1,10,100
* @param {number} num
* @param {number} digit
* @returns 当前数字 的 位数 对应的值
*/
const getNum = (num, digit) => {
// 如果 最小值 小于等于 num,说明 num 有这个位数,否则为 0
return digit <= num ? Math.floor((num / digit) % 10) : 0
}
const radix_sort = (arr) => {
// 获取最大的值
const max = Math.max(...arr)
// 定义一个桶数组,里面是10个队列
const buckets = Array.from({ length: 10 }, () => new Queue())
// 创建一个位数,循环比较
let digit = 1
while (digit <= max) {
// 循环遍历数组里的值 入队
arr.forEach((item) => {
// 获取下标后,进行入队
buckets[getNum(item, digit)].enqueue(item)
})
// 上面操作后, arr 已经没用了,进行置空操作
arr = []
// 出队
buckets.forEach((item) => {
// 如果该队列中 有值,则分别依次出队
while (!item.isEmpty()) {
arr.push(item.dequeue())
}
})
digit = digit * 10
}
return arr
}
总结
基数排序 是 非比较排序,是一种稳定的排序方式。
而且用到了 队列 的相关知识,是 计数排序 的进阶版。
缺点同计数排序一样。但是效率是比 计数排序 高。