算法回顾系列第八篇:基数排序
--------------------------------
基数排序
基本原理:
顾名思义,它是透过键值的部份资讯,将要排序的元素分配至某些“桶”中,藉以达到排序的作用。
基数排序的方式可以采用LSD(Least significant digital)或MSD(Most significant digital),LSD的排序方式由键值的最右边开始,而MSD则相反,由键值的最左边开始。
程序实现:
/**
* RadixSort:
* 分为LSD(Least significant digital)或MSD(Most significant digital),
* LSD的排序方式由键值的最右边开始,而MSD则相反,由键值的最左边开始.
*/
public class RadixSort{
/**
* LSD方式(由键值的最右边开始)
* 由于先做了低位的排序,所以当高位相等时,低位数字还是由小到大的顺序入桶的,就是说入完桶还是有序的.
* @param 待排序数组
* @param 桶个数(即Hash后存在多少种情况),此处因为是数字,所以共需要0-9个桶.
*/
public static void lsdSort(int[] number,int d){
//temp[桶个数][桶内元素个数](桶内元素最多可能是全部元素)
int[][] temp = new int[d][number.length];
//每个桶内元素的计数
int[] order = new int[d];
int maxLength = getMaxNumberLength(number);//该数组内元素的最大位数.
int current=1;//控制键值排序依据哪一位(LSD从最右起).
int currentValue=1;//位数代表的值(1-个位,10-十位,100-百位...)
int k=0;//用于标记将桶内元素复制到数组中的位置.
while(current <= maxLength) {
System.out.println("********************");
System.out.println("当前位:"+current+" 代表值:"+currentValue);
System.out.println("入桶:");
for(int i = 0; i < number.length; i++){
//Hash取放入哪个桶:除以所在位数值,再与桶总数取模(即第几个桶).
int lsd = ((number[i] / currentValue) % d);
//放入桶内哪个位置采用计数法.
temp[lsd][order[lsd]] = number[i];
//放入桶后该桶内元素计数加1.
order[lsd]++;
}
System.out.println("各桶内元素分布:"+Arrays.deepToString(temp));
System.out.println("各桶内元素计数:"+Arrays.toString(order));
System.out.println("出桶:");
for(int i = 0; i < d; i++){//顺序遍历各桶.
if(order[i] != 0){//如果桶内元素个数不为0.
for(int j = 0; j < order[i]; j++) {//遍历当前桶内元素.
number[k] = temp[i][j];//将当前桶内元素整理到数组中.
k++;//标记位右移;
temp[i][j]=0;//复制后桶内元素清0.
}
}
order[i] = 0;//每个桶内元素复制完后,桶内元素计数清0.
}
System.out.println("本趟出桶整理后:"+Arrays.toString(number));
current++;
currentValue *= 10;//LSD方式每左移一位,该位代表的值*10.
k = 0;//每趟复制结束后,标记位归0.
}
}
/**
* 取数组内元素的最大长度
*/
public static int getMaxNumberLength(int[] number){
int maxLength = 1;//最大数字长度
for(int i=0;i<number.length;i++){
int length;//当前数字长度
int k=1;//倍数
//每次循环递增10倍,一直除到0为止.
for(length=0;(number[i]/k)>0;length++){
k*=10;
}
if(length>maxLength){
maxLength=length;
}
}
return maxLength;
}
public static void main(String[] args) {
int[] data = new int[]{73,22,93,43,55,14,28,65,39,81,33,100,6};
RadixSort.lsdSort(data, 10);
System.out.println("Result:"+Arrays.toString(data));
}
}
上面程序中:
从右向左依次作为排序依据位放入桶中,并记录每个桶内的元素个数。
然后,按桶的顺序将桶内元素写入排序数组内。
依此类推,直到最高位完成排序。
由于先做了低位的排序,所以当高位相等时,低位数字还是由小到大的顺序入桶的,就是说入完桶还是有序的。
性能分析:O(d(n+radix)),n个记录,d个关键码,关键码的取值范围为radix.
空间复杂度:O(n)
稳定性:稳定。