算法回顾系列第八篇:基数排序
--------------------------------
基数排序
基本原理:
顾名思义,它是透过键值的部份资讯,将要排序的元素分配至某些“桶”中,藉以达到排序的作用。
基数排序的方式可以采用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)
稳定性:稳定。