概述
基数排序属于分配式排序,又称“桶子法”。顾名思义,其是利用多个”桶“,通过将元素按照某种顺序放入桶中,而后又按照顺序再次取出,并且重复此操作,直到完成排序的一种排序方式。
基数排序是一种非比较型整数排序算法。也就是在运行过程中不需要对值的大小进行比较。是属于一种经典的空间换时间的算法。
基数排序在面对数字位数不大时有较好的表现。
基数排序是一种稳定性算法(相同的两个元素位置在排序后保持不变),在某些时候,基数排序法的效率高于其它的稳定性排序法。
实现思路
基数排序,顾名思义,是通过对数字的基数来进行排序实现的。
在这里的基数可以理解为每一个数字不同位数上的数字。
例如:
123,在百位上的基数为1,十位上的基数为2,个位上的基数为3,通过对这些基数的排序来实现元素的排序。
基数排序的整体实现步骤如下:
1 . 按照个位数将数据分配到各个桶中:
2. 将上一次放置桶中的元素按照由基数数字从小到大,同基数先进先出的规律将数组进行一次排序。
3. 位数进一位,没有该位数的按照0处理,按照以上两步规律继续进行操作:
进行十位操作。
进行重新依次串起来数字操作:
进行十位操作后发现还有百位数字未操作,此时进行百位操作:
串起来数据:
当对所有位数操作完毕后,算法结束,数据有序。
基数排序的算法思路比较简单,就是利用上一次位数排序产生的序列,不断按照位数推进进行排序,直到最大位数操作完毕,此时算法结束。
最后再辅助一张动图帮助了解全程:
动图来源:
但是本例子中讲解基数排序还有两个问题:
-
不能处理0数据,解决方法是可以对0数据进行特殊处理。
-
不能处理负数,解决方法是开拓属于负数的10个桶,重新利用上诉思路解决。
代码演示:
public class RadixSort {
public static void main(String[] args) {
int [] arr = {9,8,7,10,123,456,789,654,321,987};
radixSort(arr);
System.out.println(Arrays.toString(arr));
}
//基数排序方法
public static void radixSort(int arr[]) {
//定义一个二维数组表示桶
//基数排序属于空间换时间的经典算法
int [][] bucket = new int [10][arr.length];
//用一个一维数组来表示每个桶存入的个数
int [] bucketElmentsCounts = new int [10];
int max = arr[0];
for(int i = 1;i < arr.length;i++) {
if(arr[i] > max) {
max = arr[i];
}
}
int maxLength = (max + "").length();
for(int i = 0,n = 1;i < maxLength;i++,n *= 10) {
//获取元素下标
for(int j = 0;j < arr.length;j++) {
//获取下标
int digitOfElement = arr[j] / n % 10;
//放桶
bucket[digitOfElement][bucketElmentsCounts[digitOfElement]++] = arr[j];
}
int index = 0;
for(int k = 0;k < bucketElmentsCounts.length;k++) {
if(bucketElmentsCounts[k]!=0) {
for(int l = 0;l < bucketElmentsCounts[k];l++) {
arr[index++] = bucket[k][l];
}
}
//把桶下表清零
bucketElmentsCounts[k] = 0;
}
}
}
}
代码参考:
复杂度
n: 数据规模
k:桶的个数
时间复杂度(平均) | 时间复杂度(最坏) | 时间复杂度(最好) | 空间复杂度 | 是否稳定 |
---|---|---|---|---|
O(n * k) | O(n * k) | O(n * k) | O(n + k) | 是 |