基数排序(Radix Sort)

基数排序不是一次把所有数字排好,而是按位一轮一轮排,并依赖“每一轮排序必须稳定”这个前提。

定义

基数排序是一种非比较排序算法,按照低位先排序,然后收集;再按照高位排序,然后再收集;依次类推,直到最高位。

核心思路

将整数按位数切割成不同的数字,然后按每个位数分别比较:

LSD(Least Significant Digit):从最低位开始排序 MSD(Most Significant Digit):从最高位开始排序

原数组: [170, 45, 75, 90, 802, 24, 2, 66]

按个位排序: [170, 90, 802, 2, 24, 45, 75, 66]
按十位排序: [802, 2, 24, 45, 66, 170, 75, 90]
按百位排序: [2, 24, 45, 66, 75, 90, 170, 802]

最终结果: [2, 24, 45, 66, 75, 90, 170, 802]

为什么稳定性是关键

按个位排完以后,十位排序必须保留个位阶段已经形成的相对次序。
如果某一轮排序不稳定,前面位数建立起来的信息就会被打乱,最后结果就不正确。

这也是为什么基数排序通常会把 计数排序 当作子过程。

复杂度分析

指标复杂度说明
时间复杂度O(d×(n+k))d是位数,k是基数(通常10)
空间复杂度O(n+k)需要额外的计数数组和输出数组
稳定性✅ 稳定使用稳定的计数排序

适用条件:

  • 整数或可以转换为整数的数据
  • 位数d不能太大

Go 代码

Go 实现

package main
 
import "fmt"
 
func countingSortByDigit(arr []int, exp int) {
    n := len(arr)
    output := make([]int, n)
    count := make([]int, 10)
 
    // 统计
    for i := 0; i < n; i++ {
        index := (arr[i] / exp) % 10
        count[index]++
    }
 
    // 累加
    for i := 1; i < 10; i++ {
        count[i] += count[i-1]
    }
 
    // 构建输出数组
    for i := n - 1; i >= 0; i-- {
        index := (arr[i] / exp) % 10
        output[count[index]-1] = arr[i]
        count[index]--
    }
 
    // 复制回原数组
    copy(arr, output)
}
 
func radixSort(arr []int) {
    if len(arr) == 0 {
        return
    }
 
    // 找最大值
    maxVal := arr[0]
    for _, num := range arr {
        if num > maxVal {
            maxVal = num
        }
    }
 
    // 对每一位进行计数排序
    for exp := 1; maxVal/exp > 0; exp *= 10 {
        countingSortByDigit(arr, exp)
    }
}
 
func main() {
    arr := []int{170, 45, 75, 90, 802, 24, 2, 66}
 
    fmt.Println("原始数组:", arr)
    radixSort(arr)
    fmt.Println("排序后:", arr)
}

易错点

基数排序最大的坑,不在按位取数,而在“适用条件”和“稳定子过程”。

  • LSD 写法通常要求每一轮都稳定。
  • 负数、变长字符串这类场景不能直接套最基础版本。
  • 位数 d 很大时,线性时间优势会被吃掉。
  • 如果只是普通通用排序题,快排 / 归并通常更直接。

算法变体

经典题目

基础应用

字符串排序

数字处理

优缺点

优点

  • ✅ 线性时间:O(d×(n+k)),d较小时很快
  • ✅ 稳定排序:保持相等元素的相对顺序
  • ✅ 不需要比较操作
  • ✅ 适合处理大量数据

缺点

  • ❌ 位数限制:位数d较大时性能差
  • ❌ 只适用于整数:或可转换为整数的数据
  • ❌ 空间复杂度高:需要O(n+k)额外空间
  • ❌ 实现复杂:比简单排序复杂

应用场景

  1. 整数排序:大量整数,位数不多
  2. 字符串排序:定长字符串
  3. 数据库排序:大量记录按字段排序
  4. 外部排序:数据量大,可以分批处理

LSD vs MSD

特性LSDMSD
排序方向从低位到高位从高位到低位
实现难度简单复杂(递归)
适用场景定长数据不定长数据
性能稳定可能提前终止

基数排序 vs 其他排序

特性基数排序计数排序快速排序
时间复杂度O(d×(n+k))O(n+k)O(n log n)
适用数据整数/字符串小范围整数通用
稳定性稳定稳定不稳定
比较排序否否是

基数排序的实际应用

相关主题


返回:排序算法 | 算法学习导航