基数排序
基数排序 是一种非比较型整数排序算法. 它的核心思想是通过将数字按位分割, 依次对每一位进行排序, 最终得到一个有序的数组. 基数排序适用于对整数或可以转化为整数的数据进行排序.
工作原理
基数排序通过将每个数字分为不同的"位"进行排序, 通常从最低位(个位)开始, 逐步向更高位(如十位, 百位等)排序, 直到最大位为止.
具体流程如下:
- 从最低位开始排序: 首先按最低位(个位)排序.
- 稳定排序: 使用稳定的排序算法(如计数排序)对每一位的数字进行排序, 确保排序时不会改变相同数字的相对位置.
- 逐位排序: 接着按十位, 百位等依次排序, 直到最大位.
- 最终有序: 经过多轮排序后, 整个数组就是有序的.
基数排序的类型
- LSD(最低位优先): 从最低位(个位)开始排序, 一直到最高位.
- MSD(最高位优先): 从最高位(最高有效位)开始排序, 一直到最低位.
通常情况下, 我们使用 LSD(最低位优先)排序.
时间复杂度
- 时间复杂度:
O(d * (n + k)),
其中n
是数据元素的数量,d
是数字的位数(即最大数字的位数),k
是每一位上的数值范围(例如, 对于十进制数,k
为 10). 当d
较小或者数据比较"均匀"时, 基数排序的性能非常好. - 空间复杂度:
O(n + k)
, 需要额外的空间来存储临时结果.
示例代码
function radixSort(arr) {
// Step 1: Find the maximum number to determine the number of digits
let max = Math.max(...arr)
// Step 2: Do counting sort for every digit. The place is 1 for the least significant digit.
let place = 1
while (max / place > 1) {
arr = countingSortForRadix(arr, place)
place *= 10
}
return arr
}
function countingSortForRadix(arr, place) {
let output = new Array(arr.length)
let count = new Array(10).fill(0)
// Step 1: Store count of occurrences in count[]
for (let i = 0; i < arr.length; i++) {
let digit = Math.floor(arr[i] / place) % 10
count[digit]++
}
// Step 2: Change count[i] so that count[i] contains actual position of this digit in output[]
for (let i = 1; i < 10; i++) {
count[i] += count[i - 1]
}
// Step 3: Build the output array using the count positions
for (let i = arr.length - 1; i >= 0; i--) {
let digit = Math.floor(arr[i] / place) % 10
output[count[digit] - 1] = arr[i]
count[digit]--
}
// Step 4: Copy the output array to arr[], so that arr[] now contains sorted numbers according to current digit
for (let i = 0; i < arr.length; i++) {
arr[i] = output[i]
}
return arr
}
优缺点
优点:
- 线性时间复杂度: 当数据范围较小, 位数较少时, 基数排序能够达到 O(n) 的时间复杂度. 尤其对于处理大数据时, 表现比比较排序算法(如快速排序, 归并排序)要好.
- 不依赖比较: 基数排序不依赖于元素之间的比较, 避免了比较排序算法中的比较开销.
缺点:
- 空间复杂度较高: 需要额外的空间来存储每一位的计数信息.
- 受数据范围限制: 基数排序对数据的位数(或数字的大小)有要求. 如果数据范围较大(例如, 数字非常大或者位数很多), 空间和时间复杂度可能会增加.
- 仅适用于整数或可以转化为整数的数据: 基数排序只能用于排序整数或可以转化为整数的数据(如浮点数, 字符串等可以通过一定方式转化为数字).
适用场景
基数排序适用于以下场景:
- 排序数字或者可以离散化为整数的数据.
- 数据规模较大, 但数据范围或位数较小的情况, 例如处理大量的数字, 电话号码, 社保号码等.
- 当要求稳定排序且不希望使用基于比较的排序算法时.
基数排序是一种高效的排序算法, 尤其在某些特定条件下, 表现出色. 但它也有一定的局限性, 特别是当处理大范围数据时, 需要合理选择使用时机.