什么是桶排序
之前了解过计数排序,所以也知道计数排序的缺点是数列取值范围过大时,空间占用大,算法效率低,或者不是整数时,没法使用的缺点。
那么计数排序这些缺点,要怎么解决呢?所以就诞生了桶排序。
说到桶,就能联想到最近比较热门的”垃圾分类”,垃圾分类需要把不同的垃圾分类到不同的桶中,再由垃圾分类员进行更近一步的垃圾分类。
因此,桶排序,也名副其实,使用桶来将数值进行归类,然后对桶内的数值进行局部排序,对排序后的桶进行合并。
桶排序当中的每一个桶,都代表一个数值的区间范围,可以承载一个或多个数值。
桶排序中的桶,此图源自小灰的文章
桶排序的第一步,便是需要得到排序要用多少个桶,每个桶又怎么分配数值的区间。这里有很多种不同的方式。
其中一种方法是使用5个桶用作排序,但是桶排序在所有元素平分到各个桶中时的表现最好。如果元素非常稀疏,则使用更多的桶会更好。如果元素非常密集,则使用较少的桶会更好。
接着确定每个桶的区间跨度,计算桶的区间跨度公式为有很多。
- 数组最大值与最大值的插值与桶大小进行除法运算。
- 数组最大值与最小值的差值与桶大小进行除法运算的向下取整数,并+1
- 数组最大值与最小值的差值与桶大小进行除法运算的向下取整数,并-1
……
根据实际情况,选用合适的区间跨度公式,能过增加桶排序的效率。
接着根据区间跨度,将数组中的数值对号入座到不同的桶中。
根据区间跨度,将数组中的数值对号入座到不同的桶中,此图源自小灰的文章
再对每个桶内部的元素进行排序,这里可以使用不同的排序算法,例如使用插入排序。
对每个桶内部的元素进行排序,此图源自小灰的文章
最后,遍历输出所有桶中的值,就能得到桶排序的结果。
代码实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
| export const Compare = { LESS_THAN: -1, BIGGER_THAN: 1, EQUALS: 0 };
export function defaultCompare(a, b) { if (a === b) { return Compare.EQUALS; } return a < b ? Compare.LESS_THAN : Compare.BIGGER_THAN; }
export const insertionSort = (array, compareFn = defaultCompare) => { const { length } = array; let temp; for (let i = 1; i < length; i++) { let j = i; temp = array[i]; while (j > 0 && compareFn(array[j - 1], temp) === Compare.BIGGER_THAN) { array[j] = array[j - 1]; j--; } array[j] = temp; } return array; };
function createBuckets(array, bucketSize) { let minValue = array[0]; let maxValue = array[0]; for (let i = 1; i < array.length; i++) { if (array[i] < minValue) { minValue = array[i]; } else if (array[i] > maxValue) { maxValue = array[i]; } } const bucketCount = Math.floor((maxValue - minValue) / bucketSize) + 1; const buckets = []; for (let i = 0; i < bucketCount; i++) { buckets[i] = []; } for (let i = 0; i < array.length; i++) { buckets[Math.floor((array[i] - minValue) / bucketSize)].push(array[i]); } return buckets; }
function sortBuckets(buckets) { const sortedArray = []; for (let i = 0; i < buckets.length; i++) { if (buckets[i] != null) { insertionSort(buckets[i]); sortedArray.push(...buckets[i]); } } return sortedArray; }
export function bucketSort(array, bucketSize = 5) { if (array.length < 2) { return array; } const buckets = createBuckets(array, bucketSize); return sortBuckets(buckets); }
|