概念
桶排序是计数排序算法的升级版本。假设输入数据服从均匀分布,将数据分到有限的数量的桶里,每个桶再分别排序。
算法原理
- 假设有如下原始数组:
[35,23,48,9,16,24,5,11,32,17]
我们可以建立五个桶,每个桶按范围顺序分别是[0,10)
、[10,20)
、[20,30)
、[30,40)
、[40,50]
,注意,每个桶的范围都是包含最小值,不包含最大值,最后一个桶,既包含最小值,也包含最大值
- 对每个桶里面的数据进行排序
- 遍历所有桶,因为每个桶都是有序的了,所以遍历所有桶也是有序的。
算法代码
/**
* 桶排序
* @param {number[]} arr 原始数组
* @param {number} bucketCapacity 桶容量
*/
function bucketSort(arr, bucketCapacity = 10) {
// 1. 先求出原始数组的最大值和最小值
let max = arr[0]
let min = arr[0]
for(let i = 1; i < arr.length; i++) {
if (arr[i] > max) {
max = arr[i]
}
if (arr[i] < min) {
min = arr[i]
}
}
// 桶的数量
const bucketCount = ~~((max - min) / bucketCapacity) + 1
// 初始化桶里数据,是一个二维数组
const bucketArr = Array(bucketCount).fill().map(() => [])
for (let i = 0; i < arr.length; i++) {
const item = arr[i]
// 计算当前元素应该放入哪个桶里面
let bucketIndex = ~~((item - min) / (max - min) * bucketCount)
if (bucketIndex === bucketCount) {
bucketIndex--
}
bucketArr[bucketIndex].push(item)
}
// 对每个桶进行排序,这里使用插入排序
for (let i = 0; i < bucketArr.length;i++) {
let itemArr = bucketArr[i]
insertionSort(itemArr)
}
// 遍历每个桶
const result = []
let index = 0
for(let itemArr of bucketArr) {
for (let item of itemArr) {
result[index++] = item
}
}
return result
}
// 插入排序
function insertionSort(array) {
for (let i = 1; i < array.length; i++) {
let insertValue = array[i]
let insertIndex = i - 1
while(insertIndex >=0 && array[insertIndex] > insertValue) {
array[insertIndex + 1] = array[insertIndex]
insertIndex--
}
array[insertIndex + 1] = insertValue
}
}