基数排序已经不再是一种常规的排序方式,它更多地像一种排序方法的应用,基数排序必须依赖于另外的排序方法。基数排序的总体思路就是将待排序数据拆分成多个关键字进行排序,也就是说,基数排序的实质是多关键字排序。
多关键字排序的思路是将待排数据里德排序关键字拆分成多个排序关键字;第1个排序关键字,第2个排序关键字,第3个排序关键字......然后,根据子关键字对待排序数据进行排序。
多关键字排序时有两种解决方案:
最高位优先法(MSD)(Most Significant Digit first)
最低位优先法(LSD)(Least Significant Digit first)
例如,对如下数据序列进行排序。
192,221,12,23
可以观察到它的每个数据至多只有3位,因此可以将每个数据拆分成3个关键字:百位(高位)、十位、个位(低位)。
如果按照习惯思维,会先比较百位,百位大的数据大,百位相同的再比较十位,十位大的数据大;最后再比较个位。人得习惯思维是最高位优先方式。
如果按照人得思维方式,计算机实现起来有一定的困难,当开始比较十位时,程序还需要判断它们的百位是否相同--这就认为地增加了难度,计算机通常会选择最低位优先法。
基数排序方法对任一子关键字排序时必须借助于另一种排序方法,而且这种排序方法必须是稳定的。
对于多关键字拆分出来的子关键字,它们一定位于0-9这个可枚举的范围内,这个范围不大,因此用桶式排序效率非常好。
对于多关键字排序来说,程序将待排数据拆分成多个子关键字后,对子关键字排序既可以使用桶式排序,也可以使用任何一种稳定的排序方法。
在基数排序算法中,没有进行关键字的比较和记录的移动,而只是顺链扫描链表和进行指针赋值,所以,排序的时间主要耗费在修改指针上。对于n个记录(假设每个记录含d个关键字,每个关键字的取值范围为rd个值)进行一趟分配的时间复杂度为O(n),进行一趟收集的时间复杂度为O(rd),整个排序过程需要进行d趟分配和收集操作。因此,链式基数排序总的时间复杂度为O(d(n+rd))。
//基数排序:基数排序的实质是多关键字排序;多关键字排序相当于将数的个,十,百,位都取出来一一进行排序。然后在每个排序的过程中
//用的是桶式排序,可以这么说,基数排序就是在总位数下的桶式排序的循环。只不过多了取各个位置上的数,和取得最大位数的操作。
public class RadixSort2 {
public static void main(String[]args){
int a[]={ 123, 321, 132, 212, 213, 312, 21, 223 };
radixSort(a);
for(int i=0;i<a.length;i++){
System.out.print(" "+a[i]);
}
}
public static int[] radixSort(int a[]){//从低位到高位的排序,先从个位排序,然后再依次排序 //返回值哦
for(int d=1;d<=getMax(a);d++){//总位数的循环,一位位的排序
int tem[]=new int[a.length ];//备用数组
int count[]=new int[10];//计次数的数组
for(int i=0;i<a.length ;i++){//桶式排序
count[digit(a[i],d)]++;
}
for(int i=1;i<a.length ;i++){
count[i]=count[i]+count[i-1];
}
System.arraycopy(a,0,tem,0,a.length);
for(int i=a.length -1;i>=0;i--){
a[--count[digit(tem[i],d)]]=tem[i];
}
//一个位数上的排序完成。进行下一个排序
}
return a;
}
public static int getMax(int a[]){//取得最大位数的操作 //返回值哦
int maxlIndex = 0;
for (int j = 1; j < a.length; j++) {
if (a[j] > a[maxlIndex]) {
maxlIndex = j;
}
}
return String.valueOf(a[maxlIndex]).length(); //输出长度值哦.这个很特别
}
public static int digit(int a,int d){//取各个位置上的数 //返回值哦
long pow = 1;
while (--d > 0) { // 看是几位的,就除以相应的数
pow *= 10;
}
return (int)(a / pow % 10); // % 求余哈
}
}