基数排序

基数排序过程无须比较关键字,而是通过“分配”和“收集”过程来实现排序。它们的时间复杂度可达到线性阶:O(n)。

实例

扑克牌中52 张牌,可按花色和面值分成两个字段,其大小关系为:

花色:梅花< 方块< 红心< 黑心

面值:2 < 3 < 4 < 5 < 6 < 7 < 8 < 9 < 10 < J < Q < K < A

若对扑克牌按花色、面值进行升序排序,得到如下序列:


即两张牌,若花色不同,不论面值怎样,花色低的那张牌小于花色高的,只有在同花色情况下,大小关系才由面值的大小确定。这就是多关键码排序。


为得到排序结果,我们讨论两种排序方法。

方法1:先对花色排序,将其分为4 个组,即梅花组、方块组、红心组、黑心组。再对每个组分别按面值进行排序,最后,将4 个组连接起来即可。

方法2:先按13 个面值给出13 个编号组(2 号,3 号,…,A 号),将牌按面值依次放入对应的编号组,分成13 堆。再按花色给出4 个编号组(梅花、方块、红心、黑心),将2号组中牌取出分别放入对应花色组,再将3 号组中牌取出分别放入对应花色组,……,这样,4 个花色组中均按面值有序,然后,将4 个花色组依次连接起来即可。

设n 个元素的待排序列包含d 个关键码{k1,k2,…,kd}(相当于花色,面值等),则称序列对关键码{k1,k2,…,kd}有序是指:对于序列中任两个记录r[i]和r[j](1≤i≤j≤n)都满足下列有序关系:


其中k1 称为最主位关键码,kd 称为最次位关键码  。


两种多关键码排序方法:

多关键码排序按照从最主位关键码到最次位关键码或从最次位到最主位关键码的顺序逐次排序,分两种方法:

最高位优先(Most Significant Digit first)法,简称MSD法:

1)先按k1 排序分组,将序列分成若干子序列,同一组序列的记录中,关键码k1 相等。

2)再对各组按k2 排序分成子组,之后,对后面的关键码继续这样的排序分组,直到按最次位关键码kd 对各子组排序后。

3)再将各组连接起来,便得到一个有序序列。扑克牌按花色、面值排序中介绍的方法一即是MSD 法。

最低位优先(Least Significant Digit first)法,简称LSD法:

1) 先从kd 开始排序,再对kd-1进行排序,依次重复,直到按k1排序分组分成最小的子序列后。

2) 最后将各个子序列连接起来,便可得到一个有序的序列, 扑克牌按花色、面值排序中介绍的方法二即是LSD 法。


基于LSD方法的链式基数排序的基本思想

“多关键字排序”的思想实现“单关键字排序”。对数字型或字符型的单关键字,可以看作由多个数位或多个字符构成的多关键字,此时可以采用“分配-收集”的方法进行排序,这一过程称作基数排序法,其中每个数字或字符可能的取值个数称为基数。比如,扑克牌的花色基数为4,面值基数为13。在整理扑克牌时,既可以先按花色整理,也可以先按面值整理。按花色整理时,先按红、黑、方、花的顺序分成4摞(分配),再按此顺序再叠放在一起(收集),然后按面值的顺序分成13摞(分配),再按此顺序叠放在一起(收集),如此进行二次分配和收集即可将扑克牌排列有序。


基数排序:

是按照低位先排序,然后收集;再按照高位排序,然后再收集;依次类推,直到最高位。有时候有些属性是有优先级顺序的,先按低优先级排序,再按高优先级排序。基数排序基于分别排序,分别收集,所以是稳定的。

#include <iostream>  
#include <queue>  
using namespace std;  
  
#define radix 10  //个位数和十位数的基数均为10
 
void radix_sort(int A[], int len)  
{  
    queue<int> list[radix]; //队列数组:数组里存的是队列 
  
    int i=1, j=0;  
    int max = A[0];  
    int base;  
    while (i<len)  
    {  
        if(max<A[i]) max=A[i];  
        i++;  
    }  
    cout<<"max: "<<max<<endl;  
    int size=0;  
    while(max>0)  
    {  
        max=max/10;  
        size++;  
    }  
    /* 
    最次位优先法(LSD法)。 
    先按k2(个位数)排序,将序列分成若干子序列(10个),每个子序列中的记录具有相同的kd值(0,1,2...); 
再按k1(十位数)排序, 最后将各个子序列(10个)连接起来,便可得到一个有序的序列。 
前面介绍的扑克牌先按面值再按花色进行排序的方法就是LSD法 
*/   
    int t = 1;  
    while(size>0)  
    {  
        //cout<<"size: "<<size<<endl;  
//------------分配过程-------------------------- //先按个位数分配,分成10个子序列,再按此顺序收集;
		//再按十位数分配,分成10个子序列,再按此顺序收集 
        for(i=0;i<len;i++)  
        {  
            base=(A[i]/t)%10;  
            list[base].push(A[i]); 
        }  
        t = t*10;  
        size--;  
//------------收集过程---------------------------  
        j=0;  
        for(i=0;i<radix;i++)  
        {  
            while(!list[i].empty())  
            {  
                A[j]=list[i].front();  
                cout<<A[j]<<" ";  
                list[i].pop();  
                j++;  
            }  
        }  
        //cout<<endl;  
    }     
}  
  
int main()  
{  
    int A[]={15,9,8,1,4,11,7,12,13,16,5,3,6,2,10,14};  
    //int A[]={13,14,94,33,82,25,59,94,65,23,45,27,73,25,39,10,35,54,90,58};  
    int i;  
    int len=sizeof(A)/sizeof(int);   
    radix_sort(A,len);  
  
    for(i=0;i<len;i++)  
    {  
        cout<<A[i]<<"  ";  
    }  
    cout<<endl;  
    return 0;  
}  


  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值