基数排序详解及代码示例

基数排序原理
基数排序通过处理每一位数字进行排序,分为 LSD(最低位优先) 和 MSD(最高位优先) 两种方式。核心步骤:
- 确定最大值:计算数组中最大数的位数。
- 逐位排序:对每一位数字使用稳定排序(如计数排序)。
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)
,因需要额外的计数数组和临时数组。 - 稳定性:所有变体均使用计数排序作为中间步骤,因此稳定性保持。