基数排序

1基数排序概念

基数排序的时间复杂度为O(n),它用于排序整数,而一般而言这个整数的基r=2,8,10,16等。最常见的就是对基为10的整数排序。若要对含小数的数进行排序(有数点在有限位中,通常为m个有效小数),则可以先把所有的数乘以10^m.再排序。

而对于长整数(这里的长整数通常是以字符串表示的),也可以从低到高进行基数排序。

基数排序(有最低位优先LSD,和最高位优先MSD两种)的直观理解就是:假设一个数表示成knkn-1...k3k2k1k0,则对一组数按LSD方式进行排序,则把这组数的最低位k0取出,然后排序,并根据k0的顺序调整原始数据的位置。依次类推,直到最高位。

注意点:对每一位进行排序时,需要使用稳定的排序算法,保证在排序高位时低位的顺序不会变

应用于高能物理实验数据的基数排序算法的文章中测试了基数的效率: 随机数据

1 5 10 15

插入排序 0.4748124 12.6790326 47.033886 108.1055356

快速排序 0.0047062 0.0284178 0.062906 0.0979182

基数排序 0.0008162 0.00475524 0.0138398 0.023450

	可以非常明显的看到基数排序与其它排序的效率不在一起数量级,而且随着数据量的增大,基数排序的优势会更大

2图例说明

如: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 

再对10位数进行排序:

0                  
1 14                
2 22 28              
3 39                
4 43                
5 55 65              
6                  
7 73                
8 81                
9 93                

 

从这个桶顺序取出

14 22 28 39 43 55 65 73 81 93
	

3.算法实现

	算法的关键点:1,如何每次取出个位、十位...2,如何保证若在同一个桶中的顺序是稳定的,
	如于2,采用队列、或链表操作可以很简单的实现,这里不介绍。在网上看到了基于计数算法实现,这在里把自己理解分析一下。
	

3.1如何每次取出个位、十位

	一种方法是转换成字符串,然后通过字符串来取,如int a=123,取十位如,
	
#include "stdio.h"
void main()
{
    int a=123;
    char buf[10];
    int index;
    sprintf(buf,"%d",a);
    index=buf[1]-'0';//十位
    printf("%d\n",index);    
}
另外一种方式,通过算术运算:不能改变原始数据
如dat=123,	取个位为dat%10=3()
取十位为:dat%100=23, 23/10=2;
取百位为:dat%1000=123,123/100=1

3.2 基于计数的基数排序

以int num[]={23,446,32,95,234,23,3,21,45,90,34,40,99};为例分析个位的排序:
int index[]={3, 6, 2, 5, 4, 3, 3, 1, 5,0, 4, 0, 9}//个位结果。
由于基数为10,因此要开辟一个空间用于计数,在基数内的每个数字出现了多少次:
int count[]={2,1,1,3,2,2,1,0,0,1}
从而我们知道在第i个桶中有多少个数据。但我们要把桶转化到一维数组中。
3.index[10]=4对应到temparr[]数组下标为:count_arr[4]-1=9-1=8; count_arr[4]-- 从而
   
   
temparr[8]=index[10]=4;;//或temparr[8]=num[10]=34;
......
13.index[0]=3,对应到temparr[]数组下标为:count_arr[3]-1=5-1=4;(之前有两个使count_arr[3]各减1,从而此处为7-2)从而
temparr[4]=index[0]=3;;//或temparr[4]=num[0]=23;
有了上面的分析,代码实现就简单了:
	
/* Note:Your choice is C IDE */
#include "stdio.h"
#include<malloc.h>
void jishu_sort(int index[],int base,int data[],int data_len){
	int i;
	int *count=(int *)malloc(sizeof(int)*base);
	int *tempdata=(int *)malloc(sizeof(int)*data_len);
	for(i=0;i<base;i++)//这相当于10个桶
		count[i]=0;
	for(i=0;i<data_len;i++)
		count[index[i]]++;	
	for(i=1;i<base;i++)
		count[i]=count[i]+count[i-1];//此时count数组为对应到一维数组的上界+1
	for(i=data_len-1;i>=0;i--){//这个是保证排序的稳定性。
		count[index[i]]--;//减1,得到数组上界,同时使下次的上界减一
		tempdata[count[index[i]]]=data[i];		
	}
	//printf("\n");
	for(i=0;i<data_len;i++){
		data[i]=tempdata[i];
		//printf("data[%d]=%d\n",i,data[i]);
	}
	//printf("\n");
	free(tempdata);
	free(count);
	
}

void main()
{
	int num[]={23,446,32,95,234,23,3,21,45,90,34,40,99};	
	int len=sizeof(num)/sizeof(int);
	int *index=(int *)malloc(sizeof(int )*len);
	int base=1,i,flag=1,j;
	printf("blog.csdn.net/lin200753\n");
	while(flag){
		base*=10;
		flag=0;
		for(j=0;j<len;j++){
			index[j]=num[j]%base;
			index[j]/=base/10;			
			if(index[j]){
				flag=1;	
			}			
		}
		if(flag){//可以进入处理,
			//for(j=0;j<len;j++)
			//	printf("index[%d]=%d,",j,index[j]);
			jishu_sort(index,10,num,len);
		}		
	//	printf("\n");		
	}
	for(i=0;i<len;i++){
		
		printf("num[%d]=%d\n",i,num[i]);
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值