基数排序

二话不说,先上代码:
接下来将重点解释有important注释的地方:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=1000005;
long long origin[N],final[N],last[N];//原始数组,当前数组,原始数组当前的关键字 
int bucket[12];//桶 
int cout=15;//位数,最大位数 
int po(int a)//乘方函数 
{
    int n=1;
    for(int i=1;i<a;++i)
    {
        n*=10;
    }
    return n;
}
int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;++i)
    {
        scanf("%d",&origin[i]);
    }
    for(int i=0;i<=cout;++i)
    {
        memset(bucket,0,sizeof(bucket));
        for(int j=1;j<=n;++j)//取出马上要排序的关键字,一般从个位开始往上取。 
        {
            last[j]=(origin[j]/po(i))%10;
            bucket[last[j]]++;//桶排操作 
        }
        for(int j=1;j<=9;++j)//求前缀和操作,就是看当前关键字,可以大概由小到大排到多少位,方便下面对最终数组进行排序! 
        {
            bucket[j]+=bucket[j-1];//☣
        }
        for(int j=n;j>=1;--j)//important 
        {
            final[bucket[last[j]]]=origin[j];
            bucket[last[j]]--;//important
        }
        for(int j=1;j<=n;++j)//赋值操作 
        {
            origin[j]=final[j];
        }
    }
    for(int i=1;i<=n;++i)//输出 
    {
        printf("%d ",final[i]);
    }
    return 0;
}

P.s:前缀和指当前所求关键字,加上自己同类的干扰(关键字一样)由小到大排到的位置(排到自己同类的最后面,最坏情况)。

重点来了!!!

important就是重点,首先我们可以发现,这里的for循环和前面的for循环有点不太一样,这个我们稍后作解释,我们先来解释一下下面的三重括号,最里面一重是当前原来数组(origin)的最后一位数;第二重就是这个最后一位数所在的桶的大概位置(前面求了前缀和,前缀和概念见前面P.s)这就是他final的位置,这个时候为了防止对后面一样的关键字有影响(两个关键字排在同一位置),所以对他的前缀和进行--操作,反正考虑的是最坏情况,也就是说,一来初始的前缀和一定是当前关键字所在桶的最后一位,所以我们进行--操作最多也就是减到第一位,并不会影响到前面一个桶,(若他是第一个桶,我相信大家照这个理解会更容易一些!)。
相信大家上面都懂了,现在我们来讲一讲细节!!!
为什么上面的for循环要反着写?
为了使我们的解释更加方便,我们在这里为大家造一组数据:

32 31 23 24

你可能会说,看上去貌似没有什么问题啊? 别急!!
首先我们先进行第一波排序,这一波以个位为关键字:
结果如下:

31 32 23 24

正常,对吧!
再来,重点来了,大家可以仔细品读下面这段话!
第二波因为是从前往后对关键字为十位来进行排序,那我们慢慢来:
1、首先23,24会被丢进二号桶,31,32会被扔进3号桶,所以2,3号桶各两个量,3号桶的前缀和为4,2号桶为2.

_2、下面进行从前往后遍历:
_

(1)首先,31,3号桶,前缀和4,扔入final数组4号位
 
  (2)其次,32,3号桶,前缀和4--=3,扔入final数组3号位(细心的朋友应该已经发现问题了!)
  
 (3)再其次,23,2号桶,前缀和2,扔入final数组2号位
 
  (4)最后,24,2号桶,前缀和2--=1,扔入final数组1号位( 又出现了同样的问题,哈哈!)

_3_最后的扯皮答案:

24 23 32 31

大家都应该知道问题在哪里了吧!因为我们要遵守优先级规则,后面的origin数组中低位一定比高位大,所以我们必须从后面开始排,否则会出现如果高位关键字的大小是一样的,那么考前面低位更小的排入final数组中反而会占据优先级更大的位置(也就是说31会在32后面!!!)

如果你是一个皮怪,“我就想这样写!!!”,你可以这样做,首先优先级变为前面所有桶的大小+1(这一步忒麻烦,还要多定一个数组,唉!),然后后面的for循环你就可以正着写,最后把--改为++;
以上就是我对这道题的所有解读,希望可以帮助到你!!!,谢谢采纳!

原文地址:https://www.cnblogs.com/mudrobot/p/13330774.html