【算法】基数排序

计数排序

学习基数排序之前首先学习计数排序。

计数排序假设每个元素都是在0到k之间的一个整数。

基数排序的基本思想,对于每个元素x,如果我们知道了小于x的元素的个数,就可以确定输出数组中元素x的位置,那么直接将元素x放到输出数组中。比如有3小于x的元素,那在输出数组中,x肯定位于第4个位置。

计数排序的算法用伪代码描述为:

COUNTING-SORT(A,k)
	// 初始化数组C
	for i=0 to k
		C[i]=0

	// 统计A[j]元素出现的次数,保存到C数组中
	for j=0 to A.length
		C[A[j]]=C[A[j]]+1

	// 统计小于等于A[j]元素的个数
	for k=0 to k
		C[K]=C[K-1]+C[K]

	// 将A中的元素放在B中正确的位置
	for i=A.length to 0
		B[C[A[i]]-1]=A[i]
		C[A[i]]=C[A[i]]-1

注:由于有可能有相同元素存在,所以,每次将A[i]元素放入B数组中,都要将C[A[j]]的值减一,这样当遇到下一个值等于A[j]的元素时,该元素就能放在输出数组中A[j]的前面。

计数排序的详细过程如下

计数排序的关键代码如下

public int[] countSort(int a[], int k) {
		int[] b = new int[a.length];
		int[] c = new int[k];
		for (int i = 0; i < c.length; i++) {
			c[i] = 0;
		}
		for (int i = 0; i < a.length; i++) {
			c[a[i]] += 1;
		}
		for (int i = 0; i < c.length; i++) {
			if (i != 0) {
				c[i] += c[i - 1];
			}
		}
		for (int i = a.length - 1; i >= 0; i--) {
			b[c[a[i]] - 1] = a[i];
			c[a[i]] = c[a[i]] - 1;
		}
		return b;
	}

计数排序的性能

很容易得到计数排序的时间复杂度为:T(n)=O(k+n),因此当k小于等于n,也就是当k=O(n),k和n同阶时,采用计数排序的时间复杂度为T(n)=O(n)

同时,计数排序也是一种稳定的排序算法。

基数排序

基数排序最初是用在打孔卡片制表机上的一种排序算法,由Herman Hollerith发明,也就是IBM的创始人。

基数排序从最低为开始来排序的,从低位到高位,按位排序,按位排序必须是稳定的。

基数排序的详细过程

基数排序算法描述为

RADIX-SORT(A,d)
	for i=1 to d
		use a stable sort to sort arrat A on digit i

在这里我们选择计数排序。考虑常规情况,对[0...9]之间的数排序,k=10,且一般有k<<n,此时能达到最好的时间复杂度O(n)

基数排序的关键代码,这里以数组排序时按照十进制每位进行比较。

/**
	 *  基数排序
	 * @param result  最终已排序的数组,共用一个节省空间
	 * @param maxLen  待排序的数组中最大的位数
	 */
	public static void radixSort(int[] a,int[] result, int maxLen) {
		int flag = 1;
		// 保存每轮要排序的位对应数组a的值
		int [] digitArr = new int[a.length];
		for(int i=0; i < maxLen; i++) {
			// 共比较的轮数
			flag *= 10;
			// b数组中对应的装着a数组中每位的数,第一轮装着各位,第二轮装着十位数...
			for (int j = 0; j < digitArr.length; j++) {
				digitArr[j]=a[j]%flag;
				digitArr[j]=digitArr[j]/(flag/10);
			}
			countSort(a, digitArr,result,10);
			// 每一轮计数排序完后刷新下一轮要排序的数组
			System.arraycopy(result, 0, a, 0,result.length);
		}
	}

调用计数排序的函数

/**
	 * 计数排序 :对数组a中的元素按某些位排序
	 * @param tmp  要参与排序的当前位的值保存在tmp中
	 * @param result  每次计数排序后的新的数组顺序
	 */
	public static void countSort(int a[], int tmp[], int result[], int k) {
		int[] c = new int[k];
		for (int i = 0; i < c.length; i++) {
			c[i] = 0;
		}
		for (int i = 0; i < tmp.length; i++) {
			c[tmp[i]] += 1;
		}
		for (int i = 0; i < c.length; i++) {
			if (i != 0) {
				c[i] += c[i - 1];
			}
		}
		for (int i = tmp.length - 1; i >= 0; i--) {
			// 和计数排序唯一的差别在于赋值的时候用真实的数据
			result[c[tmp[i]] - 1] = a[i];
			c[tmp[i]] = c[tmp[i]] - 1;
		}
	}

基数排序的性能

如果基数排序使用的稳定排序算法的时间复杂度为O(n+k),那么基数排序的时间复杂度为T(n)=O(d(n+k))

很容易理解要循环d轮,每轮耗时为O(n+k),于是总的耗时为O(d(n+k))

在此基础上,从2^r进制来看,此时k为2^r,并且一个b位数要比较b/r轮。于是我们得到T(n)=O((b/r)(n+2^r))

对上式求导可得其最小值。此时r=lgn,此时T(n)=O((b/lgn)n),如果再取b=lgn,这时就能达到最少的运行时间,时间复杂度为T(n)=O(n)

基数排序也是稳定的排序算法

时间: 2024-12-11 22:28:04

【算法】基数排序的相关文章

经典排序算法 - 基数排序Radix sort

经典排序算法 - 基数排序Radix sort 原理类似桶排序,这里总是需要10个桶,多次使用 首先以个位数的值进行装桶,即个位数为1则放入1号桶,为9则放入9号桶,暂时忽视十位数 例如 待排序数组[62,14,59,88,16]简单点五个数字 分配10个桶,桶编号为0-9,以个位数数字为桶编号依次入桶,变成下边这样 |  0  |  0  | 62 |  0  | 14 |  0  | 16 |  0  |  88 | 59 | |  0  |  1  |  2  |  3  |  4 | 

排序算法----基数排序(RadixSort(L))单链表智能版本

转载http://blog.csdn.net/Shayabean_/article/details/44885917博客 先说说基数排序的思想: 基数排序是非比较型的排序算法,其原理是将整数按位数切割成不同的数字,然后按每个位数分别比较. 将所有待比较数值(正整数)统一为同样的数位长度,数位较短的数前面补零.然后,从最低位开始,依次进行一次排序.在每一次排序中,按照当前位把数组元素放到对应 的桶当中,然后把桶0到桶9中的元素按先进先出的方式放回数组中.这样从最低位排序一直到最高位排序完成以后,

排序算法----基数排序(RadixSort(L,max))单链表版本

转载http://blog.csdn.net/Shayabean_/article/details/44885917博客 先说说基数排序的思想: 基数排序是非比较型的排序算法,其原理是将整数按位数切割成不同的数字,然后按每个位数分别比较. 将所有待比较数值(正整数)统一为同样的数位长度,数位较短的数前面补零.然后,从最低位开始,依次进行一次排序.在每一次排序中,按照当前位把数组元素放到对应 的桶当中,然后把桶0到桶9中的元素按先进先出的方式放回数组中.这样从最低位排序一直到最高位排序完成以后,

算法-基数排序(radix sort)

本文由@呆代待殆原创,转载请注明出处. 简介:这个排序是原来用在卡片排序机上的一个算法,一般用来比较具有多对关键字域的记录,如日期(年月日),通过基数排序我们会依次对年月日这三个关键字进行排序,只要对每个关键字进行排序的算法是稳定的,那么最后输出的序列就一定是正确的. 思路:基数排序思路很简单,首先取第一个关键字,然后对其进行排序,在第一次排序的基础上取第二个关键字,再对其进行排序,直到遍历完所有的关键字,一般用计数排序实现基数排序. 算法分析 时间复杂度:Θ(i*x)  i 是关键码的数量,x

排序算法——基数排序(桶式排序)

基数排序(radix sort)属于"分配式排序"(distribution sort),又称"桶子法"(bucket sort)或bin sort,顾名思义,它是透过键值的部份资讯,将要排序的元素分配至某些"桶"中,藉以达到排序的作用,基数排序法是属于稳定性的排序,其时间复杂度为O (nlog(r)m),其中r为所采取的基数,而m为堆数,在某些时候,基数排序法的效率高于其它的稳定性排序法.(引自百度百科) 简单的理解就是按权高低依次排序.比如说

排序算法--基数排序

#define _CRT_SECURE_NO_WARNINGS #include<math.h> #include <stdio.h> #include <stdlib.h> int findMaxNum(int *p, int n); void sort2(int *p, int n, int loop); void bucketSort3(int *p, int n); int getLoopTimes(int num); /* 基数排序原理: 求出数组中最大值 求

[算法]基数排序简述

在学习了计数排序后,可以发现一个很严重的问题,如果数据很大呢,不如说每个元素小于2^64 - 1,超时可能不怎么会,数据不好的 情况下会超内存 (虽然可以直接用快排,但是为了讲解基数排序还是讲一下基数排序) 基数排序可以说成是改良版的桶排,还是将一些数放入指定的桶中 比如一串数 12 33 43 54 65 39 45 72 89 首先按照个位分配到 0 - 10 这11个“桶”中 0 1 2 12 72 3 33 43 4 54 5 65 45 6 7 8 9 39 89 接着再串起来,得到了

经典排序算法---基数排序

假设原来有一串数值如下所示: 73, 22, 93, 43, 55, 14, 28, 65, 39, 81 首先根据个位数的数值,在走访数值时将它们分配至编号0到9的桶子中: 0 1 81 2 22 3 73 93 43 4 14 5 55 65 6 7 8 28 9 39 第二步 接下来将这些桶子中的数值重新串接起来,成为以下的数列: 81, 22, 73, 93, 43, 14, 55, 65, 28, 39 接着再进行一次分配,这次是根据十位数来分配: 0 1 14 2 22 28 3 3

Java排序算法——基数排序

基数排序算法的Java实现

1.基数排序算法的简单介绍 关于基数排序算法的介绍有很多资料可以通过很多途径获取.基数排序(radix sort)又称桶排序(bucket sort),相对于常见的比较排序,基数排序是一种分配式排序,即通过将所有数字分配到应在的位置最后再覆盖到原数组完成排序的过程. 基数排序算法: 是一种非比较方法实现的排序算法 基数排序算法是一种稳定的排序算法 基数排序算法的时间复杂度: 分配需要O(n),收集为O(r),其中r为分配后链表的个数,以r=10为例,则有0-9这样10个链表来将原来的序列分类.而