基数排序是一种非比较型整数排序算法,它通过按数位从低位到高位依次处理数字,将每个数字根据当前数位的数值分配到不同的“桶”中,再按桶的顺序收集回原数组,重复这一过程直到所有数位处理完毕。这种方法特别适合处理位数较少的整数,效率较高。

基数排序的基本思想

  1. 分配:按当前数位(如个位、十位、百位)将数字分配到对应的桶中。例如,个位数字为3的数放入桶3,十位数字为2的数放入桶2等。
  2. 收集:按桶的顺序(0到9)依次取出桶中的数字,放回原数组,完成一次数位的排序。
  3. 重复:对每一个数位(从低位到高位)重复上述分配和收集过程,直到所有数位处理完毕。

举例说明排序过程

以数组 [5, 3, 8, 12, 23, 100] 为例,逐步演示排序过程:

初始数组

[5, 3, 8, 12, 23, 100]

第一轮:处理个位(radix=1)

每个数的个位数字为:5(个位5)、3(个位3)、8(个位8)、12(个位2)、23(个位3)、100(个位0)。
- 分配到桶中:
桶0:[100],桶2:[12],桶3:[3, 23],桶5:[5],桶8:[8],其他桶空。
- 收集回数组:[100, 12, 3, 23, 5, 8]

第二轮:处理十位(radix=10)

每个数的十位数字为:100(十位0)、12(十位1)、3(十位0)、23(十位2)、5(十位0)、8(十位0)。
- 分配到桶中:
桶0:[100, 3, 5, 8],桶1:[12],桶2:[23],其他桶空。
- 收集回数组:[100, 3, 5, 8, 12, 23]

第三轮:处理百位(radix=100)

每个数的百位数字为:100(百位1)、3(百位0)、5(百位0)、8(百位0)、12(百位0)、23(百位0)。
- 分配到桶中:
桶0:[3, 5, 8, 12, 23],桶1:[100],其他桶空。
- 收集回数组:[3, 5, 8, 12, 23, 100]

排序完成!

Java代码实现

import java.util.ArrayList;
import java.util.List;

public class RadixSort {

    public static void radixSort(int[] arr) {
        if (arr == null || arr.length == 0) {
            return; // 空数组直接返回
        }

        // 1. 找到数组中的最大数,确定最大数位
        int max = arr[0];
        for (int num : arr) {
            if (num > max) {
                max = num;
            }
        }

        // 2. 按数位从低位到高位处理(个位、十位、百位...)
        for (int radix = 1; max / radix > 0; radix *= 10) {
            // 创建10个桶(0-9),用ArrayList动态存储元素
            List<List<Integer>> buckets = new ArrayList<>();
            for (int i = 0; i < 10; i++) {
                buckets.add(new ArrayList<>());
            }

            // 3. 分配:将每个数按当前位数字放入对应桶
            for (int num : arr) {
                int currentDigit = (num / radix) % 10; // 获取当前位数字
                buckets.get(currentDigit).add(num);
            }

            // 4. 收集:按桶顺序(0-9)放回原数组
            int index = 0;
            for (List<Integer> bucket : buckets) {
                for (int num : bucket) {
                    arr[index++] = num;
                }
            }
        }
    }

    // 测试代码
    public static void main(String[] args) {
        int[] arr = {5, 3, 8, 12, 23, 100};
        System.out.println("排序前:" + java.util.Arrays.toString(arr));
        radixSort(arr);
        System.out.println("排序后:" + java.util.Arrays.toString(arr));
    }
}

代码关键点解析

  1. 找到最大数:确定需要处理的最高数位(如最大数为100时,需处理百位)。
  2. 获取当前位:通过 (num / radix) % 10 计算当前数位。例如:
    - 个位:radix=1(num / 1) % 10 → 直接取个位。
    - 十位:radix=10(num / 10) % 10 → 取十位。
  3. 桶的分配与收集:使用 ArrayList 动态存储每个桶的元素,避免预先确定桶容量,收集时按顺序放回原数组。

时间与空间复杂度

  • 时间复杂度O(d*(n+k)),其中 d 是最大数的位数,n 是数组长度,k 是基数(此处 k=10)。若 dk 固定,时间复杂度近似 O(n)
  • 空间复杂度O(n+k),需 n 个空间存储数组,k 个桶。

总结

基数排序通过“按位分配-收集”的方式实现排序,适合整数排序,尤其当数字位数较少时效率较高。代码中使用 ArrayList 作为桶,简化了动态存储过程,且保持了排序的稳定性(相同数字相对顺序不变)。对于负数,可先分离正负再分别排序,最后合并。

小夜