基数排序必须依赖于另外的排序方法。基数排序的基总体思路就是将待排数据拆分成多个关键字进行排序,也就是说,基数排序的实质是多关键字排序。
多关键字排序的思路是将待排数据里的排序关键字拆分成多个排序关键字:第一个自关键字。第二个自关键字。第三个自关键字……然后,根据子关键字对待排数据进行排序。
在进行对关键字排序时有两种解决方案。
1.最高位优先法MSD(Most Significant Digit first)
2.最低位优先法LSD(Least Significant Digit first)
例如,对如下数据序列进行排序:
192, 221, 13, 23
可以观察到它的每个数据之多只有 3 位,因此可以将每个数据拆分成 3 个关键字:百位(高位),十位,个位(低位)。
如果按照习惯思维,会先比较高位,高位大的数据大;高位相同时再去比较下一位,下一位大的数据大;若前面几位都相同最后比较个位,个位大的数据大。人的思维习惯是最高位优先方式。
但如果按照人的思维方式,计算机实现起来会比较麻烦,不是吗 ?所以我们通常用计算机选择最低优先算法,如下所示。
第一轮先比较个位,对个位关键字排序后得到序列为:
221, 192, 13, 23
第二轮比较十位,对十位关键字排序后得到序列为:
13, 23, 221, 192
第三轮在比较百位,对百位关键字排序后得到序列为:
13, 23, 192, 221
从上面介绍可以看出,基数排序方法对任一个子关键字排序时必须借助于另一种排序算法,而这种排序方法必须是稳定。
如过这种算法不稳定,比如上面排序过程中,经过第二轮排序后,13 位于 23 之前,在第三轮排序时,如果排序算法是稳定的,那么 13 还是位于 23 之前,如果 不稳定,则有可能导致 23 最后位于 13 之前,这就导致了最终排序结果出现错误。
现在的稳定是,对子关键字进行排序是,到底选用哪种排序呢,从已有的排序算法来看,桶式排序算法,归并排序算法,Shell(希尔)排序算法(关于Shell排序稳不稳定实验结果知道),折半插入排序算法,直接插入排序算法,冒泡排序算法,都是稳定的算法,到底选哪种,答案是桶式排序算法。
回顾桶式排序算法的两个要求:
1、待排序列的所有值处于一个可枚举的范围内。
2、待排序列所在的这个可枚举范围不应该太大,否则排序开销太大。
对于多关键字拆分出来的子关键字,他们一定位于 0 ~ 9 这个可枚举的范围之内,这个范围也不大。因此选择桶式排序是最好的。
代码实现:
package com.yc.imp.sort;
import java.util.Arrays;
public class MultiKeyRadixSort {
/**
*
* @param data :待排数组
* @param radix :指定关键字拆分的进制,如 radix=10,表示按十进制拆分
* @param d :指定将关键字拆分成一个子关键字
*/
public static void radixSort(int[] data, int radix, int d){
System.out.println("-开始排序-");
int arrayLength = data.length;
//需要一个临时数组
int[] temp = new int[arrayLength];
//bucktes数组是桶式排序的必要数组
int[] buckets = new int[radix];
for(int i = 0,rate = 1; i < d; i ++){
Arrays.fill(buckets, 0);
System.arraycopy(data, 0, temp, 0, arrayLength);
//计算每个待排数据的子关键字
for(int j = 0; j < arrayLength; j ++){
//计算指定位置上的子关键字
int subKey = (temp[j] / rate) % radix;
buckets[subKey] ++;
}
for(int j = 1; j < radix; j ++){
buckets[j] = buckets[j] + buckets[j - 1];
}
for(int m = arrayLength - 1; m >= 0; m --){
int subKey = (temp[m] / rate) % radix;
data[ --buckets[subKey] ] = temp[m];
}
System.out.println( "对"+ rate + "为子关键字排序:"+ Arrays.toString(data));
rate *= radix;
}
System.out.println("-排序结束-");
}
public static void main(String[] args){
int[] data = {1100, 192, 221, 12, 23};
System.out.println( "-排序前-" + Arrays.toString(data));
radixSort(data, 10, 4);
System.out.println( "-排序后-" + Arrays.toString(data));
}
}