概述
基数排序(Radix Sort)是一种非比较型整数排序算法,适用于整数或固定长度的字符串排序。它的基本思想是将待排序的元素分为多个关键字进行排序,通常从最低位(最低有效位,Least Significant Digit, LSD)到最高位(最高有效位,Most Significant Digit, MSD)逐位进行排序。
基数排序可以利用计数排序(Counting Sort)或桶排序作为子程序来实现单个位上的排序。这使得基数排序在特定场合下非常高效,能够以线性时间复杂度 O(d⋅(n+k))O(d \cdot (n + k))O(d⋅(n+k)) 完成排序,其中 ddd 是数字的位数,nnn 是数组的元素数量,kkk 是基数(例如 10 对于十进制数)。
算法步骤
- 确定最大位数:找出数组中最大数的位数(最大数字决定了要排序的轮数)。
- 逐位排序:从最低有效位(LSD)到最高有效位(MSD)逐位进行排序。
- 使用稳定排序算法:通常使用计数排序来保证每个位上的排序是稳定的。
应用场景
基数排序适用于需要对大规模整数数据进行排序的场合,尤其是当数值位数较小时。它常用于电话号码、身份证号等固定长度的数字或字符串排序。在不要求原地排序的情况下,基数排序可以高效地处理大规模数据集。
算法特点
- 时间复杂度:O(d⋅(n+k))O(d \cdot (n + k))O(d⋅(n+k)),其中 ddd 是数字的位数,kkk 是基数。
- 空间复杂度:需要额外的空间用于计数排序,因此空间复杂度为 O(n+k)O(n + k)O(n+k)。
- 稳定性:是稳定的排序算法,因为使用稳定的子排序算法。
示例代码
下面是一个用 Java 实现的基数排序示例代码,针对整数数组:
import java.util.Arrays;
public class RadixSort {
// 获取数组中的最大值,用于确定最大位数
private static int getMax(int[] arr) {
int max = arr[0];
for (int num : arr) {
if (num > max) {
max = num;
}
}
return max;
}
// 对数组的某个位进行计数排序
private static void countingSort(int[] arr, int exp) {
int n = arr.length;
int[] output = new int[n];
int[] count = new int[10]; // 基数是10
// 统计出现的次数
for (int num : arr) {
int index = (num / exp) % 10;
count[index]++;
}
// 更新计数数组,计算累计计数
for (int i = 1; i < 10; i++) {
count[i] += count[i - 1];
}
// 构建输出数组
for (int i = n - 1; i >= 0; i--) {
int num = arr[i];
int index = (num / exp) % 10;
output[count[index] - 1] = num;
count[index]--;
}
// 将排序结果复制回原数组
System.arraycopy(output, 0, arr, 0, n);
}
// 基数排序主函数
public static void radixSort(int[] arr) {
int max = getMax(arr);
// 从最低有效位开始排序
for (int exp = 1; max / exp > 0; exp *= 10) {
countingSort(arr, exp);
}
}
public static void main(String[] args) {
int[] arr = {170, 45, 75, 90, 802, 24, 2, 66};
System.out.println("排序前数组:");
System.out.println(Arrays.toString(arr));
radixSort(arr);
System.out.println("排序后数组:");
System.out.println(Arrays.toString(arr));
}
}
代码解析
- 获取最大值:通过
getMax
方法获取数组中的最大值,确定排序次数。 - 计数排序:
countingSort
方法对数组的每一位进行计数排序,参数exp
表示当前排序的位数。 - 逐位排序:通过
exp
逐位递增,对每个位进行排序。 - 输出数组构建:在计数排序中,通过逆序遍历原数组来保证稳定性。
优缺点
- 优点:
- 可以实现线性时间复杂度的排序,特别是在位数有限的情况下。
- 是稳定的排序算法。
- 缺点:
- 需要额外的空间来存储计数和输出数组。
- 只能用于整数或固定长度的字符串排序。
- 对于非常大的整数(位数过多)时,效率可能不如其他线性排序算法。
总结
基数排序是一种高效的非比较排序算法,在特定场合能够以线性时间完成排序。它特别适合用于对整数或固定长度的字符串进行排序。在实现过程中,通常与计数排序结合使用,以确保排序的稳定性和高效性。