排序之基数排序

本文介绍了基数排序的基本思想和实现过程,它通过“分配”和“收集”而非关键字比较来排序,适合固定长度的整数排序。文章还提供了具体的算法步骤和伪代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

          排序之基数排序

     下面介绍一种比较“特别”的排序算法,前面讨论的几种算法均是基于关键字之间的比较来实现的,而基数排序则是通过“分配”和“收集”过程来实现排序的,不需要进行关键字间的比较,是一种借助多关键字排序的思想对单关键字排序的方法。其实通俗的来讲,基数排序的思想类似于我们对数字进行比较大小的思路,逐位的来进行比较。基数排序的关键就在于按位进行“分配”和“收集”,接下来我们详细讨论。

    一般元素a[i]的关键字a[i].key是由d位数字组成,即k(d-1)k(d-2)….k(0),每一个数字表示关键字的一位,其中k(d-1)为最高位,k(0)为最低位,每一位的值都在0<=k(i)<r范围内,其中,r称为基数(也就是进制数)。例如,对于十进制r为10,对于二进制r为2。我们采用最低优先方式,过程为:我们先对最低位进行排序,在此基础上,然后再对次高位进行排序,依此类推,由低位到高位,每趟都是根据关键字的一位并在前一趟的基础上对所有元素排序,直至最高位。

   在这里我们采用线性表的链式存储结构(单链表)来对程序进行描述,假设线性表由节点a0,a1,……,a(n-1)构成,每个节点的关键字由d位组成,其中每一位的数字为k(0<=k<r),r为基数,在排序过程中需要使用r个链队Q0,Q1…..Q(r-1)(所以空间复杂度为O(r)),排序过程如下:
   对i=0,1,….,,d-1,依次做一次“分配”和“收集”。

   分配过程:开始时,把Q0,Q1,….,Q(r-1)各个链队置为空,然后依次考察线性表中的每一个节点a(i)(i=0,1,….n-1),如果a(i)的关键字为k,就把a(i)插入到Q(k)链表中,采用尾插法。

   收集过程:将Q0,Q1,….Q(r-1)各个队列中的节点依次首尾相接,得到新的节点序列,从而形成新的线性表。具体过程下面给出代码来解释,在给出代码前,先举例说明一下“分配”和“收集”过程:

    待排序序列: 23  42  45  36  78  66  80  84

    按个位数字进行分配 → 收集     →  按十位数字进行分配  →  收集(序列有序 )

                               

 typedef struct node

{
       chardata[MAXD];//MAXD为最大的关键字位数
       structnode *next;
}RecType;
 
void RadixSort (RecType * &p, int r,int d)
//实现基数排序,p为待排序序列单链表指针,r为基数,d为关键字位数
{
       RecType*head[MAXR], *tail[MAXR], *t; //定义各链队的首位指针
       inti,j,k;
       for(i=d-1; i>=0; i--)//从低位到高位循环进行“分配”和“收集”
       {
              for(j=0;j<r; j++)//初始化各链队首位指针
                     head[j]= tail[j] = NULL;
              while(p!= NULL) //找到第k个链队
              {
                     k= p->data[i] - '0';
                     if(head[k]= NULL)//第k个链队首尾为空时,队头队尾均指向*p
                     {
                            head[k]= p;
                            tail[k]= p;
                     }
                     else
                     {
                            tail[k]->next= p;//第k个链队非空时,尾插法插入*p
                            tail[k]= p;
                     }
                     p= p->next;
              }
                //分配完成,下面开始收集
              p=NULL;//重新用p来收集所有节点
              for(j=0;j<r; j++) //收集:对于每一个链队循环
                   {
                       if(head[j] != NULL) //若第j个链队是第一个非空链队
                     {
                            if(p== NULL)
                            {
                                   p= head[j];
                                   t= tail[j];
                            }
                            else   //若第j个链队是其他非空链队
                            {
                                   t->next= head[j];
                                   t= tail[j];
                            }
                     }
                     t->next= NULL;
                        //最后一个节点的next域置NULL,至此一次分配收集过程结束
                   }
       }
}
   我们不难分析出,在基数排序过程中,共进行了d遍的分配和收集,每一遍分配和收集的时间为O(n+r),所以基数排序的时间复杂度为O(d(n+r))。这也就说明了,当待排序序列的位数过大或者各个数字的位数差距较大时,不适宜使用基数排序

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值