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]); } }