基数排序是一种排序算法,它通过首先对相同位值的各个数字进行分组来对元素进行排序。然后,根据元素的递增/递减顺序对元素进行排序。
假设我们有一个包含 8 个元素的数组。首先,我们将根据单位位置的值对元素进行排序。然后,我们将根据第十位的值对元素进行排序。这个过程一直持续到最后一个重要的地方。
设初始数组为[121, 432, 564, 23, 1, 45, 788]。如下图所示按照基数排序。
![]() |
---|
基数排序的工作 |
请在阅读本文之前先了解计数排序,因为计数排序是基数排序中的一种中间排序。
算法的图解
- 找到数组中最大的元素,即 最大值. 让X成为 中的位数max。X计算是因为我们必须遍历所有元素的所有重要位置。
在这个数组中[121, 432, 564, 23, 1, 45, 788],我们有最大的数字 788。它有 3 位数字。因此,循环应该达到数百个位置(3 次)。
- 现在,一个一个地浏览每一个重要的地方。
使用任何稳定的排序技术对每个重要位置的数字进行排序。我们为此使用了计数排序。
根据单位位数字 ( X=0)对元素进行排序。
![]() |
---|
使用计数排序根据单位位置对元素进行排序 |
- 现在,根据十位数字对元素进行排序。
|
| | —- | | 根据十位对元素进行排序 |
- 最后,根据百位的数字对元素进行排序。
|
| | —- | | 根据数百个位置对元素进行排序 |
算法的伪码
radixSort(array)
d <- maximum number of digits in the largest element
create d buckets of size 0-9
for i <- 0 to d
sort the elements according to ith place digits using countingSort
countingSort(array, d)
max <- find largest element among dth place elements
initialize count array with all zeros
for j <- 0 to size
find the total count of each unique digit in dth place of elements and
store the count at jth index in count array
for i <- 1 to max
find the cumulative sum and store it in count array itself
for j <- size down to 1
restore the elements to array
decrease count of each element restored by 1
算法的实现
// Radix Sort in Java Programming
import java.util.Arrays;
class RadixSort {
// Using counting sort to sort the elements in the basis of significant places
void countingSort(int array[], int size, int place) {
int[] output = new int[size + 1];
int max = array[0];
for (int i = 1; i < size; i++) {
if (array[i] > max)
max = array[i];
}
int[] count = new int[max + 1];
for (int i = 0; i < max; ++i)
count[i] = 0;
// Calculate count of elements
for (int i = 0; i < size; i++)
count[(array[i] / place) % 10]++;
// Calculate cumulative count
for (int i = 1; i < 10; i++)
count[i] += count[i - 1];
// Place the elements in sorted order
for (int i = size - 1; i >= 0; i--) {
output[count[(array[i] / place) % 10] - 1] = array[i];
count[(array[i] / place) % 10]--;
}
for (int i = 0; i < size; i++)
array[i] = output[i];
}
// Function to get the largest element from an array
int getMax(int array[], int n) {
int max = array[0];
for (int i = 1; i < n; i++)
if (array[i] > max)
max = array[i];
return max;
}
// Main function to implement radix sort
void radixSort(int array[], int size) {
// Get maximum element
int max = getMax(array, size);
// Apply counting sort to sort elements based on place value.
for (int place = 1; max / place > 0; place *= 10)
countingSort(array, size, place);
}
// Driver code
public static void main(String args[]) {
int[] data = { 121, 432, 564, 23, 1, 45, 788 };
int size = data.length;
RadixSort rs = new RadixSort();
rs.radixSort(data, size);
System.out.println("Sorted Array in Ascending Order: ");
System.out.println(Arrays.toString(data));
}
}
算法复杂度
时间复杂度 | |
---|---|
最好的 | O(n+k) |
最差 | O(n+k) |
平均 | O(n+k) |
空间复杂度 | O(max) |
稳定 | 是的 |
由于基数排序是一种非比较算法,因此它相比比较排序算法具有优势。对于使用计数排序作为中间稳定排序的基数排序,时间复杂度为O(d(n+k))。
这里,d是循环数,O(n+k)是计数排序的时间复杂度。因此,基数排序具有比O(nlog n)比较排序算法更好的线性时间复杂度。如果我们采用非常大的数字或其他基数,如 32 位和 64 位数字,那么它可以在线性时间内执行,但是中间排序需要很大的空间。这使得基数排序空间效率低下。这就是为什么在软件库中不使用这种排序的原因。
算法的应用
- DC3 算法 (Kärkkäinen-Sanders-Burkhardt) 同时制作后缀数组。
- 有大范围数字的地方。
相似的算法
- 快速排序
- 归并排序
- 桶排序
- 计数排序