🎯 什麼情境該想到我

當你「要排大量的整數、固定長度字串、IP、日期、定長 ID」的時候。
★ 它把 計數排序 的「值域不能大」限制解掉了——代價是輸入必須能被拆成幾個位數。

⚙️ 怎麼用(機制與推導)

運作機制:LSD(從最低位開始)

輸入:329  457  657  839  436  720  355

① 排個位數(穩定排序)
   720  355  436  457  657  329  839
     ↑0   ↑5   ↑6   ↑7   ↑7   ↑9   ↑9
                    ★ 457 在 657 前面 —— 因為上一輪它就在前面(穩定性)

② 排十位數
   720  329  436  839  355  457  657

③ 排百位數
   329  355  436  457  657  720  839    ← 完成
// 排非負整數,base 通常取 256(每輪處理一個 byte)
func RadixSort(a []uint32) {
    const base = 256
    buf := make([]uint32, len(a))
    for shift := 0; shift < 32; shift += 8 {
        var count [base]int
        for _, v := range a {
            count[(v>>shift)&(base-1)]++
        }
        for i := 1; i < base; i++ {
            count[i] += count[i-1]
        }
        // ★ 從後往前 —— 穩定性
        for i := len(a) - 1; i >= 0; i-- {
            d := (a[i] >> shift) & (base - 1)
            count[d]--
            buf[count[d]] = a[i]
        }
        a, buf = buf, a           // 交換角色,省掉一次 copy
    }
    // 32/8 = 4 輪(偶數),結果正好回到 a
}

★ 為什麼「必須從最低位開始」而且「必須用穩定排序」

這是這題唯一真正的考點。

LSD 的正確性完全依賴穩定性。

排到第 位時,前 位已經排好了。
穩定排序保證:第 位相同的元素,維持它們原本(也就是低位已排好)的相對順序。
所以每一輪結束後,「後 位」都是正確排序的。

如果內層排序不穩定,低位的排序成果在高位那一輪就會被打亂,整個演算法錯誤。

為什麼不從高位開始(MSD):MSD 也可行,但每個前綴群組要各自遞迴,需要管理大量子問題的邊界——
實作複雜得多。好處是可以提前結束(前綴已經區分出來就不用往下排),所以變長字串排序用 MSD。

LSDMSD
方向低位 → 高位高位 → 低位
需要穩定內層✅ 必須不需要
實作簡單(迴圈)複雜(遞迴 + 分組)
提前結束❌ 一定要跑完所有位✅
適合定長整數變長字串

複雜度

  • = 位數(以基底 計)
  • = 基底(每輪的值域)

基底的取捨:

base32 位元整數的輪數 每輪 count 陣列
101010
256(1 byte)4256 ← 實務常用
65536(2 bytes)265,536

★ base 越大輪數越少,但 count 陣列越大(可能超出快取)。
256 是常見的甜蜜點:正好一個 byte,位移與遮罩都是單一指令,count 陣列 1 KB 完全在 L1 快取內。

什麼時候真的比快排快

  • 很大( 以上)
  • 鍵是定長整數
  • 實測上常見 2–3 倍的差距(但必須自己量,取決於資料與硬體)

🧪 我實際套用的紀錄

  • (待填)

⚠️ 注意 / 什麼時候不適用

  • ★ 有符號整數要先處理。直接對負數的二補數表示做位元比較會錯(負數的最高位是 1,會被排到後面)。標準做法是把最高位翻轉(v ^ 0x80000000)再排。
  • 浮點數也可以排,但要轉換:IEEE 754 正數可直接比位元,負數要整個翻轉。這是個有名的技巧,但容易寫錯。
  • 變長字串用 MSD,或先補齊到定長(補齊會浪費空間)。
  • ★ 不是「線性」。 對 32 位元整數是 4,對 128 位元 UUID 是 16—— 會吃掉優勢。
  • 要 的額外空間(輸出緩衝區)。
  • ★ 實務上幾乎不用自己寫。標準庫的排序已經高度優化且泛用;基數排序只在明確量測到排序是瓶頸、且鍵是定長整數時才值得。
  • 內層一定要穩定(見上面的推導)。

🔗 相關工具