多关键字排序

本文介绍了多关键字排序的最高位优先和最低位优先方法,重点讲解了链式基数排序的思想、过程和算法实现,包括关键字的位数、基数,以及排序过程中涉及的分配和收集步骤。通过示例展示了排序过程,并分析了链式基数排序的时间复杂度和空间复杂度。

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

 

设有n个记录{R1, R2, …,Rn},每个记录Ri的关键字是由若干项(数据项)组成,即记录Ri的关键字Key是若干项的集合: {Ki1, Ki2, …,Kid}(d>1) 。记录{R1, R2, …,Rn}有序的,指的是"i, j∈[1,n],i<j ,若记录的关键字满足:

{Ki1, Ki2, …Kid}<{Kj1, Kj2, …Kjd},即Kip ≤Kjp (p=1, 2, … d)        

 

多关键字排序思想

先按第一个关键字K1进行排序,将记录序列分成若干个子序列,每个子序列有相同的K1值;然后分别对每个子序列按第二个关键字K2进行排序,每个子序列又被分成若干个更小的子序列;如此重复,直到按最后一个关键字Kd进行排序。

最后,将所有的子序列依次联接成一个有序的记录序列,该方法称为最高位优先(Most Significant Digit first)。

另一种方法正好相反,排序的顺序是从最低位开始,称为最低位优先(Least Significant Digit first)。

 

链式基数排序

若记录的关键字由若干确定的部分(又称为 “位”)组成,每一位(部分)都有确定数目的取值。对这样的记录序列排序的有效方法是基数排序。

设有n个待排序记录{R1, R2, …,Rn}, (单)关键字是由d位(部分)组成,每位有r种取值,则关键字R[i].key可以看成一个d元组: R[i].key={Ki1, Ki2, …,Kid} 。

基数排序可以采用前面介绍的MSD或LSD方法。以下以LSD方法讨论链式基数排序。

 

1  排序思想

⑴  首先以静态链表存储n个待排序记录,头结点指针指向第一个记录结点;

⑵  一趟排序的过程是:

①  分配: 按Kd值的升序顺序,改变记录指针,将链表中的记录结点分配到r个链表(桶)中,每个链表中所有记录的关键字的最低位(Kd)的值都相等,用f[i]、e[i]作为第i个链表的头结点和尾结点;

②   收集:改变所有非空链表的尾结点指针,使其指向下一个非空连表的第一个结点,从而将r个链表中的记录重新链接成一个链表;

⑶  如此依次按Kd-1, Kd-2, … K1分别进行,共进行d趟排序后排序完成。

 

2  排序示例

设有关键字序列为1039, 2121, 3355, 4382, 66, 118的一组记录,采用链式基数排序的过程如下图10-12所示。

 

3  链式基数排序算法

为实现基数排序,用两个指针数组来分别管理所有的缓存(桶),同时对待排序记录的数据类型进行改造,相应的数据类型定义如下:

#define BIT_key  8    /*  指定关键字的位数d  */

#define RADIX  10    /*  指定关键字基数r  */

typedef  struct  RecType

         char  key[BIT_key] ;      /*  关键字域  */

         infoType  otheritems ;

         struct  RecType  *next ;

}SRecord, *f[RADIX] ,*e[RADIX] ;

/*   桶的头尾指针数组   */

void Radix_sort(SRecord *head )

{  

         int j, k, m ;

         SRecord  *p, *q, *f[RADIX], *e[RADIX] ;

         for (j=BIT_key-1; j>=0; j--)  

                    /*  关键字的每位一趟排序  */

         { 

                   for (k=0; k<RADIX; k++)

                        f[k]=e[k]=NULL ;   /*  头尾指针数组初始化  */

                            p=head ;

                   while (p!=NULL)      /*  一趟基数排序的分配  */

                {  

                            m=ord(p->key[j]) ;   /*  取关键字的第j位kj   */

                    if  (f[m]==NULL)  f[m]=p ;

                    else  e[m]->next=p ;

                    p=p->next ;

               }

                   head=NULL ;    /*  以head作为头指针进行收集  */

                   q=head ;      /*  q作为收集后的尾指针  */

                   for (k=0; k<RADIX; k++)

                { 

                            if  (f[k]!=NULL)   /*  第k个队列不空则收集  */

                   { 

                                     if  (head!=NULL)  q->next=f[k] ;

                         else  head=f[k] ;

                         q=e[k] ;

                   }

               }      /*  完成一趟排序的收集   */

                   q->next=NULL ;     /*  修改收集链尾指针   */

         }

}

 

则链式基数排序的时间复杂度为: O(d(n+r))

在排序过程中使用的辅助空间是:2r个链表指针, n个指针域空间,则空间复杂度为:O(n+r)

基数排序是稳定的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值