现在的位置: 首页 > 综合 > 正文

基数排序

2014年02月24日 ⁄ 综合 ⁄ 共 2510字 ⁄ 字号 评论关闭

基数排序(radix sort)则是属于“分配式排序”(distribution sort),基数排序法又称“桶子法”(bucket sort)或bin sort,顾名思义,它是透过键值的部份资讯,将要排序的元素分配至某些“桶”中,藉以达到排序的作用,基数排序法是属于稳定性的排序,其时间复杂度为O (nlog(r)m),其中r为所采取的基数,而m为堆数,在某些时候,基数排序法的效率高于其它的比较性排序法。

效率分析:
时间效率:设待排序列为n个记录,d个关键码,关键码的取值范围为radix,则进行链式基数排序的时间复杂度为O(d(n+radix)),其中,一趟分配时间复杂度为O(n),一趟收集时间复杂度为O(n),共进行d趟分配和收集。 空间效率:需要2*radix个指向队列的辅助空间,以及用于静态链表的n个指针。

实现方法:
最高位优先(Most Significant Digit first)法,简称MSD法:先按k1排序分组,同一组中记录,关键码k1相等,再对各组按k2排序分成子组,之后,对后面的关键码继续这样的排序分组,直到按最次位关键码kd对各子组排序后。再将各组连接起来,便得到一个有序序列。 最低位优先(Least Significant Digit first)法,简称LSD法:先从kd开始排序,再对kd-1进行排序,依次重复,直到对k1排序后便得到一个有序序列。

代码示例:

public class JishuPaixu2 {
	
	public static void sort(int[] number, int d) {
		int k = 0;
		int n = 1;
		int m = 1;
		int[][] temp = new int[number.length][number.length];
		int[] order = new int[number.length];
		while (m <= d) {
			for (int i = 0; i < number.length; i++) {
				int lsd = ((number[i] / n) % 10);
				temp[lsd][order[lsd]] = number[i];
				order[lsd]++;
			}
			
			for (int i = 0; i < d; i++) {
				if (order[i] != 0)
					for (int j = 0; j < order[i]; j++) {
						number[k] = temp[i][j];
						k++;
					}
				order[i] = 0;
			}
			n *= 10;
			k = 0;
			m++;
		}
	}

	public static void main(String[] args) {
		int[] data = { 73, 22, 93, 43, 55, 14, 28, 65, 39, 81, 33, 100 };
		
		JishuPaixu2.sort(data, 10);
		
		for (int i = 0; i < data.length; i++) {
			System.out.print(data[i] + " ");
		}
	}
	
	
}

基数排序一般仅是用于记录的关键字为整数类型的情况。

在已介绍的各种内部排序方法中,就所需要的计算时间来看,快速排序、归并排序、堆排序是很好的方法。但是,归并排序需要大小为n的辅助空间,快速排序需要一个栈。除了快速排序、堆排序、选择排序、希尔排序不稳定外,其它排序方法都是稳定的。

评价一个排序算法性能好坏的主要标准是它所需的计算时间和存储空间。影响计算时间的两个重要因素是比较关键字的次数和记录的移动次数。在实际应用中,究竟应该选用何种排序方法,取决于具体的应用和机器条件。 

第二种实现方式:

import java.util.ArrayList;
import java.util.List;

public class JishuPaixu {

	public static void main(String[] args) {
		int a[] = { 7, 3, 9, 8 };
		
		sort(a);

		for (int i = 0; i < a.length; i++) {
			System.out.print(a[i] + "->");
		}

	}

	public static void sort(int[] array) {
		// 首先确定排序的趟数:找出数组中最大的那个数,然后不断对10取余,记录次数,就是这个数组的比较的次数
		int max = array[0];
		for (int i = 1; i < array.length; i++) {
			if (array[i] > max) {
				max = array[i];
			}
		}

		int time = 0;

		// 判断位数
		while (max > 0) {
			max /= 10;
			time++;
		}
		
		// 建立10个队列
		List<ArrayList<Integer>> queue = new ArrayList<ArrayList<Integer>>();
		for (int i = 0; i < 10; i++) {
			ArrayList<Integer> queue1 = new ArrayList<Integer>();
			queue.add(queue1);
		}

		// 进行time次分配和收集
		for (int i = 0; i < time; i++) {
			// 分配数组元素;
			for (int j = 0; j < array.length; j++) {
				// 得到数字的第time+1位数
				int x = array[j] % (int) Math.pow(10, i + 1)
						/ (int) Math.pow(10, i);
				ArrayList<Integer> queue2 = queue.get(x);
				queue2.add(array[j]);
				queue.set(x, queue2);
			}
			
			// 元素计数器
			int count = 0;
			// 收集队列元素
			for (int k = 0; k < 10; k++) {
				while (queue.get(k).size() > 0) {
					ArrayList<Integer> queue3 = queue.get(k);
					array[count] = queue3.get(0);
					queue3.remove(0);
					count++;

				}
			}
		}

	}

}

 

参考链接:

1.http://www.cnblogs.com/sun/archive/2008/06/26/1230095.html(对排序的原理和稳定排序解释的不错)

2.http://blog.csdn.net/pzhtpf/article/details/7560312 (有很好的图文讲解,特别容易理解)

抱歉!评论已关闭.