基数排序算法原理及实现和优化
基数排序不同于之前所介绍的各类排序,前边介绍到的排序方法或多或少的是通过使用比较和移动记录(元素)来实现排序,而基数排序的实现不需要进行对关键字的比较,只需要对关键字进行“分配”与“收集”两种操作即可完成。
基数排序的原理(实现的逻辑步骤)
- 例如对无序表
{50,123,543,187,49,30,0,2,11,100}
进行基数排序,由于每个关键字都是整数数值,且其中的最大值由个位、十位和百位构成,每个数位上的数字从
0
到9
,首先将各个关键字按照其个位数字的不同进行分配分配表如下图所示:
- 通过按照各关键字的个位数进行分配,将分配到每一行的数据按放入时的顺序取出后得到的序列为:
{50,30,0,100,11,2,123,543,187,49}
。在该序列表的基础上,再按照各关键字的十位数字对各关键字进行分配,得到的分配表如下图所示:
- 由上表顺序收集得到的记录表为:
{0,100,2,11,123,30,543,49,50,187}
。在该无序表的基础上,依次将表中的记录按照其关键字的百位数字进行分配,得到的分配如下图所示:
- 最终通过三次分配与收集,最终得到的就是一个排好序的有序表:
{0,2,11,30,49,50,100,123,187,543}
。 - 例子中是按照个位-十位-百位的顺序进行基数排序,此种方式是从最低位开始排序,所以被称为最低位优先法(简称“LSD法”)。
基数排序的拓展
同样还可以按照百位-十位-各位的顺序进行排序,称为最高位优先法(简称“MSD法”),使用该方式进行排序同最低位优先法不同的是:当无序表中的关键字进行分配后,相当于进入了多个子序列,后序的排序工作分别在各个子序列中进行(最低位优先法每次分配与收集都是相对于整个序列表而言的)。
- 例如还是对{50,123,543,187,49,30,0,2,11,100}使用最高位优先法进行排序,首先按照百位的不同进行分配,得到的分配表为:
- 由上图所示,整个无序表被分为了 3 个子序列,序列 1 和序列 2 中含有多个关键字,序列 3
中只包含了一个关键字,最高位优先法完成排序的标准为:直到每个子序列中只有一个关键字为止,所以需要分别对两个子序列进行再分配,各自的分配表如下图所示:
- 上表中,序列 1 中还有含有两个关键字的子序列,所以还需要根据个位进行分配,最终按照各子序列的顺序同样会得到一个有序表。
基数排序的具体实现(采用LSD法)
具体的实现代码为:
如果代码看不明白可以先看看这里:基于基数排序实现的桶排序
public class RadixSort {
public static void main(String[] args) {
int[] data = {51, 944, 1, 9, 57, 366, 79, 6, 1, 345};// 待排序数组
sort(data, 3);
print(data);
}
/**
* 从小到大排序
* @param data 待排序数组
* @param d 表示最大的数有多少位
*/
public static void sort(int[] data, int d) {
int n = 1;
// 数组的第一维表示可能的余数0-9
int[][] bask = new int[10][data.length];
// 数组index[i]用来表示该位(个、十、百.......)是 i 的数的个数
int[] index = new int[10];
// i:控制键值排序依据在哪一位(个、十、百.......)
for (int i = 0; i < d; i++) {
for (int j = 0; j < data.length; j++) {
int lsd = ((data[j] / n) % 10);
bask[lsd][index[lsd]++] = data[j];
}
int pos = 0;
for (int j = 0; j < 10; j++) {
for (int k = 0; k < index[j]; k++) {
data[pos++] = bask[j][k];
}
index[j] = 0;
}
n *= 10;
}
}
public static void print(int array[]) {
for (int j = 0; j < array.length; j++) {
System.out.printf("%5d", array[j]);
}
System.out.println();
}
}
基数排序的特点及性能
基数排序(radix sort)属于“分配式排序”(distribution sort),又称“桶子法”(bucket sort)或bin sort,顾名思义,它是透过键值的部份资讯,将要排序的元素分配至某些“桶”中,藉以达到排序的作用,基数排序法是属于稳定性的排序,其时间复杂度为O (nlog®m),其中r为所采取的基数,而m为堆数,在某些时候,基数排序法的效率高于其它的稳定性排序法。