一、基本思想
1、基数排序(Radix Sort)是一种借助于多关键字排序的思想对单逻辑关键字进行排序的方法,即先将关键字分解成若干部分,然后通过对各部分关键字的分别排序,最终完成对全部记录的排序。对记录关键字进行定义时,总是要规定其长度和组成的字符。这样,可以把d位关键字看作d个关键字组成的一个多关键字。
基数排序首先把每个关键字看作为一个d元组:
Ki=( Ki0, Ki1,…,Kid-1)
设有n个记录的序列 {R1,R2,...,Rn},且每个记录Ri含有d个关键字(Ki1,Ki2,...,Kid),则称序列{R1,R2,…,Rn}对关键字(K1,K2,…,Kd)有序指:对任意两个记录Ri和Rj(1<=i<j<=n)都满足下列有序关系:
(Ki1,Ki2,...,Kid)<(Kj1,Kj2,...,Kjd)
其中K1为最高位关键字,Kd为最低位关键字。
例如,若关键字是3位数字组成,可以看作(k1,k2,k3)三个关键字组成。有5个字母组成的关键字可看成(k1,k2,k3,k4,k5)五个关键字组成。由数字组成的关键字有10个不同的取值,其“基”为10;字母组成的关键字有26个不同取值,其“基”为26。“基”指关键字取值的范围。
2、基数排序,一般有两种方法。一种是先对主关键字K0进行排序,将序列分成若干个子序列,每个子序列都有相同的K0值,然后分别就每个子序列对关键字K1进行排序,按K1值不同再把其分成若干个更小的子序列,依次重复,直到对Kd-2进行排序后,最后所有子序列依次联接在一起成为一个有序序列,我们称之为最高位优先法(MSD,Most Significiant Digit First);另一种是从最次位Kd-1优先排序,然后对高一位的Kd-2进行排序,依次重复,直至对K0进行排序后便成为一个有序序列,我们称之为最低位优先法LSD(Least Significant Digit First)。我们这里介绍的基数排序方法就是借助“分配”和“收集”两种操作对单逻辑关键字进行排序的一种方法。设关键字的基为rd,从关键字低位起,按关键字的不同值将序列中记录“分配”到rd个队列中,再从小到大顺序“收集”起来,如此重复d次。
3、我们用静态链表存储n个待排记录,令表头记录指向第一个记录。用链表表示队列。队列头、尾指针放入数组中。第一趟分配对最低数位关键字进行,改变记录的指针值将链表中的记录分配到链队列中去。第一趟收集是改变所有非空队列的队尾记录的指针域,令其指向下一个非空队列的头指针,重新将这几个队列中的记录链接成一个链表。接着进行第二趟分配和收集,依次,至对每个关键字都进行了分配的收集,完毕。
如图中所示:
4、复杂度
空间分析:空间复杂度为O(n+2rd)(n个指针域,2rd个队列指针)
时间分析:共进行d遍,每趟要分配n个记录,收集时调整rd个尾指针。因此,算法时间复杂度为O(d(n+rd)),当n比rd大得多时,O(d*n),若d为常数,则为O(n).
基数排序是稳定的。
5、静态链表
二、算法的C语言描述
1、存储结构
2、算法描述
三、算法的C语言实现
#include"stdio.h"
#include"stdlib.h"
#include"math.h"
#include"string.h"
#define OK 1
#defineMAX_NUM_OF_KEY 8
#define RADIX 10
#define MAX_SPACE10000
#define N 10
typedef intKeyType;
typedef intInfoType;
typedef structRedType
{
KeyType key;
InfoTypeotherinfo;
}RedType;
typedef charKeysType; //定义关键字类型为字符型
typedef struct
{
KeyTypekeys[MAX_NUM_OF_KEY];
InfoTypeotheritems;
int next;
}SLCell;
typedef struct
{
SLCellr[MAX_SPACE]; //r[0]为头结点
int keynum;
int recnum;
}SLList;
typedef intArrType[RADIX];
void InitList(SLList &L,RedType D[],int n)
{ // 初始化静态链表L(把数组D中的数据存于L中)
char c[MAX_NUM_OF_KEY],c1[MAX_NUM_OF_KEY];
int i,j,max=D[0].key; // max为关键字的最大值
for(i=1;i<n;i++)
if(max<D[i].key)
max=D[i].key;
L.keynum=int(ceil(log10(max)));
L.recnum=n;
for(i=1;i<=n;i++)
{
L.r[i].otheritems=D[i-1].otherinfo;
itoa(D[i-1].key,c,10); // 将10进制整型转化为字符型,存入c
for(j=strlen(c);j<L.keynum;j++) // 若c的长度<max的位数,在c前补'0'
{
strcpy(c1,"0");
strcat(c1,c);
strcpy(c,c1);
}
for(j=0;j<L.keynum;j++)
{
L.r[i].keys[j]=c[L.keynum-1-j];
printf("%c ",L.r[i].keys[j]);
}
printf("\n");
}
}
int ord(char c)
{ // 返回k的映射(个位整数)
return c-'0';
}
void Distribute(SLCell r[],int i,ArrTypef,ArrType e) // 算法10.15
{ // 静态键表L的r域中记录已按(keys[0],…,keys[i-1])有序。本算法按
// 第i个关键字keys[i]建立RADIX个子表,使同一子表中记录的keys[i]相同。
// f[0..RADIX-1]和e[0..RADIX-1]分别指向各子表中第一个和最后一个记录
int j,p;
for(j=0;j<RADIX;++j)
f[j]=0; // 各子表初始化为空表
for(p=r[0].next;p;p=r[p].next)
{
j=ord(r[p].keys[i]); // ord将记录中第i个关键字映射到[0..RADIX-1]
if(!f[j])
f[j]=p;
else
r[e[j]].next=p;
e[j]=p; // 将p所指的结点插入第j个子表中
}
}
int succ(int i)
{ // 求后继函数
return ++i;
}
void Collect(SLCell r[],ArrType f,ArrType e)
{ // 本算法按keys[i]自小至大地将f[0..RADIX-1]所指各子表依次链接成
// 一个链表,e[0..RADIX-1]为各子表的尾指针。
int j,t;
for(j=0;!f[j];j=succ(j)); // 找第一个非空子表,succ为求后继函数
r[0].next=f[j];
t=e[j]; // r[0].next指向第一个非空子表中第一个结点
while(j<RADIX-1)
{
for(j=succ(j);j<RADIX-1&&!f[j];j=succ(j)); // 找下一个非空子表
if(f[j])
{ // 链接两个非空子表
r[t].next=f[j];
t=e[j];
}
}
r[t].next=0; // t指向最后一个非空子表中的最后一个结点
}
void printl(SLList L)
{ // 按链表输出静态链表
int i=L.r[0].next,j;
while(i)
{
for(j=L.keynum-1;j>=0;j--)
printf("%c",L.r[i].keys[j]);
printf(" ");
i=L.r[i].next;
}
}
void RadixSort(SLList &L)
{ // L是采用静态链表表示的顺序表。对L作基数排序,使得L成为按关键字
// 自小到大的有序静态链表,L.r[0]为头结点。
int i;
ArrType f,e;
for(i=0;i<L.recnum;++i)
L.r[i].next=i+1;
L.r[L.recnum].next=0; // 将L改造为静态链表
for(i=0;i<L.keynum;++i)
{ // 按最低位优先依次对各关键字进行分配和收集
Distribute(L.r,i,f,e); // 第i趟分配
Collect(L.r,f,e); // 第i趟收集
printf("第%d趟收集后:\n",i+1);
printl(L);
printf("\n");
}
}
void print(SLList L)
{ // 按数组序号输出静态链表
int i,j;
printf("keynum=%drecnum=%d\n",L.keynum,L.recnum);
for(i=1;i<=L.recnum;i++)
{
printf("keys=");
for(j=L.keynum-1;j>=0;j--)
printf("%c",L.r[i].keys[j]);
printf(" otheritems=%dnext=%d\n",L.r[i].otheritems,L.r[i].next);
}
}
#define N 10
int main()
{
RedTyped[N]={{278,1},{109,2},{63,3},{930,4},{589,5},{184,6},{505,7},{269,8},{8,9},{83,10}};
SLList l;
InitList(l,d,N);
printf("排序前(next域还没赋值):\n");
print(l);
RadixSort(l);
printf("排序后(静态链表):\n");
print(l);
return OK;
}