基数排序

匿名 (未验证) 提交于 2019-12-02 23:40:02
基数排序是一种高效的排序算法,多用于处理字符串(不支持负数,实数排序效率不高)

・ 基数排序就是以每一位的数值为关键字来排序,也就是说,是按位排序(一般从低位向高位枚举)

先贴代码

inline void Qsort(){     for(int i=0;i<M;++i) b[i]=0;// b[i]表示 i 这个数值出现了多少次     for(int i=1;i<=n;i++) b[(a[i]/base)%10]++,rank[i]=0;//统计所有数当前位的数值个数     for(int i=1;i<M;i++) b[i]+=b[i-1];//做前缀和     for(int i=n;i>=1;i--)         rank[b[(a[i]/base)%10]--]=a[i];//稍后会讲     for(int i=1;i<=n;i++) a[i]=rank[i];//把排好序的数赋给原数组 }  inline void sort(){     int max=0;     for(int i=1;i<=n;i++)         if(a[i]>max) max=a[i]; //统计最大值,最大值的位数决定了此次基数排序需要枚举的位数     while(max/base){//如果当前位没有大于最大数的最高位,说明排序没有完成         Qsort();//基数排序         base=(base<<1)+(base<<3);//枚举下一位     } }

样例

8 54 23 674 12 544 32 9 142

首先,按个位为关键字排序,统计数值
b 0 0 3 1 3 0 0 0 0 1

然后到了

for(int i=n;i>=1;i--)     rank[b[(a[i]/base)%10]--]=a[i];

怕了吧
(a[i]/base)%10 表示当前位的数值
b[(a[i]/base)%10] 表示当前位的数值有多少个,但是刚刚我们做了前缀和,它的意义就变成了小于等于这个数值的数有多少个
小于等于这个数值的数的个数,不就是当前数的排名吗?!所以我们直接把它的排名赋成这个值

于是排名就变成了

接下来来到第二位 十位
同样的,统计个数 b 1 1 1 1 2 1 0 1 0 0
我们发现 0 这个数值的一位累计了 1,这是怎么回事,似乎没有 0 啊? 考虑到有一个数是 9 ,它没有十位了,于是十位就是 0 (前导零)。这样对排序有什么影响吗? 因为这一位的数值为 0 ,肯定是最小的,排在最前面,与正确排序结果相同
补张图:

第二位排序后:

以此类推,最后的排序结果为:

这也是基数排序的核心了,假设我们现在正在排十位,显然个位已经是排好的。我们现在取出数组中的第 i 个,假设这一位的数值之前在枚举 i+1 到 n 的时候就出现过,位置为 j ,那么显然 a[j] 的个位是大于 a[i] 的个位的 ,再回到代码 rank[b[(a[i]/base)%10]--]=a[i]; 中的 b[・・・]--,也就是说 a[i] 现在刚好排在了 a[j] 的前一位,又有 a[i]<a[j] ,则满足升序,最终答案正确(实在不懂得小伙伴可以边啃代码边模拟一下)

大概就这样了吧,贴上完整代码:

#include<stdio.h> #define M 10 #define N 100007  template<class T> inline void read(T &x){     T flag=1;x=0;char c=getchar();     while(c<'0'||c>'9'){if(c=='-')flag=-1;c=getchar();}     while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-48;c=getchar();}     x*=flag; }  int a[N],base=1,n,b[M]={0},rank[N]; inline void Qsort(){     for(int i=0;i<M;++i) b[i]=0;     for(int i=1;i<=n;i++) b[(a[i]/base)%10]++,rank[i]=0;     for(int i=1;i<M;i++) b[i]+=b[i-1];     for(int i=n;i>=1;i--)         rank[b[(a[i]/base)%10]--]=a[i];     for(int i=1;i<=n;i++) a[i]=rank[i]; } inline void sort(){     int max=0;     for(int i=1;i<=n;i++)         if(a[i]>max) max=a[i];      while(max/base){         Qsort();         base=(base<<1)+(base<<3);     } } int main(){     read(n);     for(int i=1;i<=n;++i) read(a[i]);     sort();     for(int i=1;i<=n;++i) printf("%d ",a[i]); } /* 8 54 23 674 12 544 32 9 142 */

QWQ
(未完待续)

转载请标明出处:基数排序
文章来源: 基数排序
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!