基数排序(Radix Sort)是一种非比较型整数排序算法,其原理是将整数按位数切割成不同的数字,然后按每个位数分别比较。它通过从最低位(个位)开始排序,然后逐渐转向最高位,对每一位进行稳定的排序(使用计数排序或桶排序),从而达到整体排序的目的。
算法原理
基数排序的工作原理如下:
- 找出最大数的位数:确定排序的轮数,即从个位开始,到最大数的位数结束。
- 按位进行排序:从最低位(个位)开始,对每一位进行排序。可以使用计数排序或桶排序来完成这一步骤。
- 重复步骤:对每一位进行排序后,移动到下一位,重复排序过程,直到所有位数都被排序。
算法实现
以下是基数排序的Java实现示例:
java
import java.util.Arrays;
public class RadixSortExample {
public static void main(String[] args) {
int[] arr = {170, 45, 75, 90, 802, 24, 2, 66};
radixSort(arr);
System.out.println("Sorted array: " + Arrays.toString(arr));
}
public static void radixSort(int[] arr) {
if (arr == null || arr.length == 0) {
return;
}
// 找到最大数的位数
int max = Arrays.stream(arr).max().getAsInt();
int significantDigits = (int) Math.log10(max) + 1; // 以10为底的对数
// 从个位开始,按位进行排序
for (int i = 1; i <= significantDigits; i *= 10) {
countingSortByDigit(arr, i);
}
}
private static void countingSortByDigit(int[] arr, int digit) {
int n = arr.length;
int[] output = new int[n];
int[] count = new int[10];
// 计算频率数组
for (int i = 0; i < n; i++) {
int digitValue = (arr[i] / digit) % 10;
count[digitValue]++;
}
// 累计频率
for (int i = 1; i < 10; i++) {
count[i] += count[i - 1];
}
// 根据频率数组和当前位的值,放置到输出数组
for (int i = n - 1; i >= 0; i--) {
int digitValue = (arr[i] / digit) % 10;
output[count[digitValue] - 1] = arr[i];
count[digitValue]--;
}
// 将输出数组复制回原数组
System.arraycopy(output, 0, arr, 0, n);
}
}
算法适用性
基数排序适用于以下场景:
- 待排序数组中的元素是整数或可以转换为整数的字符串。
- 待排序数组中的元素位数固定或相差不大。
算法优缺点
优点:
- 基数排序可以实现线性时间复杂度 O(nk),其中 n 是待排序数组的长度,k 是最大数的位数。
- 基数排序是一种稳定的排序算法,相同元素的相对顺序保持不变。
缺点:
- 基数排序需要额外的空间来存储计数数组和输出数组。
- 当元素的位数非常大时,基数排序可能需要较长的预处理时间和额外空间。
通过理解和实践基数排序,你可以在面试中更好地展示你的算法能力和问题解决技巧。希望这些信息能够帮助你在面试中取得成功。
题目 1:实现基本的基数排序
描述 :
给定一个非负整数数组 arr
,实现一个基数排序算法对其进行排序。
要求:
- 不使用任何现成的排序库或函数。
- 保持排序的稳定性。
示例 :
输入:[170, 45, 75, 90, 802, 24, 2, 66]
输出:[2, 24, 45, 66, 75, 90, 170, 802]
Java 源码:
java
import java.util.Arrays;
public class RadixSortExample1 {
public static void main(String[] args) {
int[] arr = {170, 45, 75, 90, 802, 24, 2, 66};
radixSort(arr);
System.out.println("Sorted array: " + Arrays.toString(arr));
}
public static void radixSort(int[] arr) {
if (arr == null || arr.length == 0) {
return;
}
int max = Arrays.stream(arr).max().getAsInt();
int significantDigits = (int) Math.log10(max) + 1;
for (int i = 1; i <= significantDigits; i *= 10) {
countingSortByDigit(arr, i);
}
}
private static void countingSortByDigit(int[] arr, int digit) {
int n = arr.length;
int[] output = new int[n];
int[] count = new int[10];
// 计算频率数组
for (int i = 0; i < n; i++) {
int digitValue = (arr[i] / digit) % 10;
count[digitValue]++;
}
// 累计频率
for (int i = 1; i < 10; i++) {
count[i] += count[i - 1];
}
// 根据频率数组和当前位的值,放置到输出数组
for (int i = n - 1; i >= 0; i--) {
int digitValue = (arr[i] / digit) % 10;
output[count[digitValue] - 1] = arr[i];
count[digitValue]--;
}
// 将输出数组复制回原数组
System.arraycopy(output, 0, arr, 0, n);
}
}
题目 2:基数排序处理负数
描述 :
给定一个包含负数的整数数组 arr
,使用基数排序算法对其进行排序。
要求:
- 能够处理负数。
- 保持排序的稳定性。
示例 :
输入:[-12, -3, 0, 5, -17, 50, 6, 2]
输出:[-17, -12, -3, 0, 2, 5, 6, 50]
Java 源码:
java
import java.util.Arrays;
public class RadixSortExample2 {
public static void main(String[] args) {
int[] arr = {-12, -3, 0, 5, -17, 50, 6, 2};
radixSort(arr);
System.out.println("Sorted array: " + Arrays.toString(arr));
}
public static void radixSort(int[] arr) {
if (arr == null || arr.length == 0) {
return;
}
int max = Arrays.stream(arr).max().getAsInt();
int min = Arrays.stream(arr).min().getAsInt();
int significantDigits = (int) Math.log10(Math.abs(max) + 1) + 1;
for (int i = 1; i <= significantDigits; i *= 10) {
countingSortByDigit(arr, i, min);
}
}
private static void countingSortByDigit(int[] arr, int digit, int min) {
int n = arr.length;
int[] output = new int[n];
int[] count = new int[10];
// 计算频率数组
for (int i = 0; i < n; i++) {
int digitValue = ((arr[i] - min) / digit) % 10;
count[digitValue]++;
}
// 累计频率
for (int i = 1; i < 10; i++) {
count[i] += count[i - 1];
}
// 根据频率数组和当前位的值,放置到输出数组
for (int i = n - 1; i >= 0; i--) {
int digitValue = ((arr[i] - min) / digit) % 10;
output[count[digitValue] - 1] = arr[i];
count[digitValue]--;
}
// 将输出数组复制回原数组
System.arraycopy(output, 0, arr, 0, n);
}
}
题目 3:基数排序字符串数组
描述 :
给定一个字符串数组 arr
,其中每个字符串表示一个整数,使用基数排序算法对这些整数进行排序。
要求:
- 字符串可能包含前导零。
- 保持排序的稳定性。
示例 :
输入:["100", "3", "20", "10"]
输出:["3", "10", "100", "20"]
Java 源码:
java
import java.util.Arrays;
public class RadixSortExample3 {
public static void main(String[] args) {
String[] arr = {"100", "3", "20", "10"};
radixSort(arr);
System.out.println("Sorted array: " + Arrays.toString(arr));
}
public static void radixSort(String[] arr) {
if (arr == null || arr.length == 0) {
return;
}
int maxLen = Arrays.stream(arr).map(String::length).max().getAsInt();
for (int i = 1; i <= maxLen; i++) {
countingSortByDigit(arr, i);
}
}
private static void countingSortByDigit(String[] arr, int digit) {
int[] count = new int[10];
String[] output = new String[arr.length];
// 计算频率数组
for (String s : arr) {
int digitValue = (s.charAt(digit - 1) - '0');
count[digitValue]++;
}
// 累计频率
for (int i = 1; i < 10; i++) {
count[i] += count[i - 1];
}
// 根据频率数组和当前位的值,放置到输出数组
for (int i = arr.length - 1; i >= 0; i--) {
String s = arr[i];
int digitValue = (s.charAt(digit - 1) - '0');
output[count[digitValue] - 1] = s;
count[digitValue]--;
}
// 将输出数组复制回原数组
System.arraycopy(output, 0, arr, 0, arr.length);
}
}
这些题目和代码示例可以帮助你更好地理解和掌握基数排序算法,以及如何在实际问题中应用这一算法。在面试中,你可能会遇到类似的问题,希望这些示例能够帮助你做好准备。