算法回顾之八:基数排序

算法回顾系列第八篇:基数排序

--------------------------------

基数排序

 

基本原理:

顾名思义,它是透过键值的部份资讯,将要排序的元素分配至某些“桶”中,藉以达到排序的作用。

基数排序的方式可以采用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)

稳定性:稳定。

你可能感兴趣的:(基数排序)