【java实现+4种变体完整例子】排序算法中【基数排序】的详细解析,包含基础实现、常见变体的完整代码示例,以及各变体的对比表格

基数排序详解及代码示例


基数排序原理

基数排序通过处理每一位数字进行排序,分为 LSD(最低位优先)MSD(最高位优先) 两种方式。核心步骤:

  1. 确定最大值:计算数组中最大数的位数。
  2. 逐位排序:对每一位数字使用稳定排序(如计数排序)。

1. 标准LSD基数排序(处理正整数)

代码示例
java 复制代码
public class RadixSort {
    public static void radixSort(int[] arr) {
        if (arr == null || arr.length == 0) return;

        int max = Arrays.stream(arr).max().getAsInt();
        for (int exp = 1; max / exp > 0; exp *= 10) {
            countSort(arr, exp);
        }
    }

    private static void countSort(int[] arr, int exp) {
        int[] output = new int[arr.length];
        int[] count = new int[10]; // 0-9

        Arrays.fill(count, 0);

        // 统计当前位数字的出现次数
        for (int value : arr) {
            count[(value / exp) % 10]++;
        }

        // 累加计数
        for (int i = 1; i < 10; i++) {
            count[i] += count[i - 1];
        }

        // 反向填充输出数组(保证稳定性)
        for (int i = arr.length - 1; i >= 0; i--) {
            int index = (arr[i] / exp) % 10;
            output[count[index] - 1] = arr[i];
            count[index]--;
        }

        // 替换原数组
        System.arraycopy(output, 0, arr, 0, arr.length);
    }

    public static void main(String[] args) {
        int[] arr = {170, 45, 75, 90, 802, 24, 2, 66};
        radixSort(arr);
        System.out.println(Arrays.toString(arr)); // [2, 24, 45, 66, 75, 90, 170, 802]
    }
}

2. 处理负数的LSD变体

代码示例

通过偏移将负数转换为正数后再排序:

java 复制代码
public static void radixSortWithNegative(int[] arr) {
    if (arr == null || arr.length == 0) return;

    int min = Arrays.stream(arr).min().getAsInt();
    if (min < 0) {
        // 将所有数偏移到非负区间
        for (int i = 0; i < arr.length; i++) {
            arr[i] += -min;
        }
    }

    int max = Arrays.stream(arr).max().getAsInt();
    for (int exp = 1; max / exp > 0; exp *= 10) {
        countSort(arr, exp);
    }

    // 恢复原始值
    if (min < 0) {
        for (int i = 0; i < arr.length; i++) {
            arr[i] += min;
        }
    }
}

3. 基数为16的基数排序(十六进制)

代码示例
java 复制代码
public static void radixSortBase16(int[] arr) {
    int max = Arrays.stream(arr).max().getAsInt();
    for (int exp = 1; max / exp > 0; exp *= 16) {
        countSortBase16(arr, exp);
    }
}

private static void countSortBase16(int[] arr, int exp) {
    int[] output = new int[arr.length];
    int[] count = new int[16]; // 0-15

    Arrays.fill(count, 0);

    for (int value : arr) {
        int digit = (value / exp) % 16;
        count[digit]++;
    }

    for (int i = 1; i < 16; i++) {
        count[i] += count[i - 1];
    }

    for (int i = arr.length - 1; i >= 0; i--) {
        int digit = (arr[i] / exp) % 16;
        output[count[digit] - 1] = arr[i];
        count[digit]--;
    }

    System.arraycopy(output, 0, arr, 0, arr.length);
}

4. MSD基数排序(递归实现)

代码示例
java 复制代码
public static void msdRadixSort(int[] arr) {
    msdSort(arr, 0, arr.length - 1, 1); // 从最低位开始(假设初始位权为1)
}

private static void msdSort(int[] arr, int low, int high, int exp) {
    if (low >= high) return;

    // 使用计数排序处理当前位
    int[] count = new int[10];
    for (int i = low; i <= high; i++) {
        count[(arr[i] / exp) % 10]++;
    }

    // 累加计数并移动元素
    for (int i = 1; i < 10; i++) {
        count[i] += count[i - 1];
    }

    int[] temp = new int[arr.length];
    for (int i = high; i >= low; i--) {
        int digit = (arr[i] / exp) % 10;
        temp[count[digit] - 1] = arr[i];
        count[digit]--;
    }

    // 回填到原数组
    for (int i = low; i <= high; i++) {
        arr[i] = temp[i];
    }

    // 递归处理高位
    for (int i = 0; i < 10; i++) {
        if (count[i] > 0) {
            msdSort(arr, low, low + count[i] - 1, exp * 10);
            low += count[i];
        }
    }
}

变体对比表格

变体名称 差异描述 时间复杂度 空间复杂度 稳定性
标准LSD 处理正整数,从最低位到最高位排序 O(nk) O(n + k) 稳定
负数LSD变体 处理负数,通过偏移转换为正数 O(nk) O(n + k) 稳定
基数为16的变体 每位基数为16,适用于十六进制 O(nk) O(n + 16) 稳定
MSD基数排序 从最高位开始,递归处理各桶 O(nk) O(n + k) 稳定

关键说明

  • 时间复杂度O(nk),其中 n 是元素数量,k 是位数。
  • 空间复杂度 :通常为 O(n + k),因需要额外的计数数组和临时数组。
  • 稳定性:所有变体均使用计数排序作为中间步骤,因此稳定性保持。
相关推荐
折哥的程序人生 · 物流技术专研18 小时前
Java面试85题图解版(一):基础核心篇
java·开发语言·后端·面试
AllData公司负责人18 小时前
通过Postgresql同步到Doris,全视角演示AllData数据中台核心功能效果,涵盖:数据入湖仓,数据同步,数据处理,数据服务,BI可视化驾驶舱
java·大数据·数据库·数据仓库·人工智能·python·postgresql
Hello.Reader18 小时前
算法基础(十)——分治思想把大问题拆成小问题
java·开发语言·算法
一只大袋鼠18 小时前
JavaWeb四种文件上传方式(下篇)
java·开发语言·springmvc·javaweb
TE-茶叶蛋19 小时前
深入研究 yudao-framework 模块:Java 编程能力提升指南
java·开发语言
逻辑驱动的ken19 小时前
Java高频考点场景题24
java·开发语言·面试·职场和发展·求职招聘
绛橘色的日落(。・∀・)ノ19 小时前
机器学习之评估与偏差方差分析
算法
兔小盈19 小时前
多线程-(五)线程安全之内存可见性
java·开发语言·多线程
消失的旧时光-194319 小时前
C语言对象模型系列(四)《Linux 内核里的 container_of 到底是什么黑魔法?》—— 一篇讲透 Linux 内核的“对象模型”核心技巧
linux·c语言·算法
CeshirenTester20 小时前
LangChain的工具调用 vs 原生Skill API:性能差在哪儿?
java·人工智能·langchain