基数排序是一种借助多关键字排序思想对单关键字进行排序的方法,它是借助“分配”和“收集”2种操作对单关键字进行排序的。
链式基数排序程序:
c1.h
/**/
/* c1.h (程序名) */
#include < string .h >
#include < ctype.h >
#include < malloc.h > /**/ /* malloc()等 */
#include < limits.h > /**/ /* INT_MAX等 */
#include < stdio.h > /**/ /* EOF(=^Z或F6),NULL */
#include < stdlib.h > /**/ /* atoi() */
#include < io.h > /**/ /* eof() */
#include < math.h > /**/ /* floor(),ceil(),abs() */
#include < process.h > /**/ /* exit() */
/**/ /* 函数结果状态代码 */
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
/**/ /* #define OVERFLOW -2 因为在math.h中已定义OVERFLOW的值为3,故去掉此行 */
typedef int Status; /**/ /* Status是函数的类型,其值是函数结果状态代码,如OK等 */
typedef int Boolean; /**/ /* Boolean是布尔类型,其值是TRUE或FALSE */
#include < string .h >
#include < ctype.h >
#include < malloc.h > /**/ /* malloc()等 */
#include < limits.h > /**/ /* INT_MAX等 */
#include < stdio.h > /**/ /* EOF(=^Z或F6),NULL */
#include < stdlib.h > /**/ /* atoi() */
#include < io.h > /**/ /* eof() */
#include < math.h > /**/ /* floor(),ceil(),abs() */
#include < process.h > /**/ /* exit() */
/**/ /* 函数结果状态代码 */
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
/**/ /* #define OVERFLOW -2 因为在math.h中已定义OVERFLOW的值为3,故去掉此行 */
typedef int Status; /**/ /* Status是函数的类型,其值是函数结果状态代码,如OK等 */
typedef int Boolean; /**/ /* Boolean是布尔类型,其值是TRUE或FALSE */
c10-3.h
/**/
/* c10-3.h 基数排序的数据类型 */
#define MAX_NUM_OF_KEY 8 /* 关键字项数的最大值 */
#define RADIX 10 /* 关键字基数,此时是十进制整数的基数 */
#define MAX_SPACE 1000
typedef struct
... {
KeysType keys[MAX_NUM_OF_KEY]; /**//* 关键字 */
InfoType otheritems; /**//* 其它数据项 */
int next;
} SLCell; /**/ /* 静态链表的结点类型 */
typedef struct
... {
SLCell r[MAX_SPACE]; /**//* 静态链表的可利用空间,r[0]为头结点 */
int keynum; /**//* 记录的当前关键字个数 */
int recnum; /**//* 静态链表的当前长度 */
} SLList; /**/ /* 静态链表类型 */
typedef int ArrType[RADIX]; /**/ /* 指针数组类型 */
#define MAX_NUM_OF_KEY 8 /* 关键字项数的最大值 */
#define RADIX 10 /* 关键字基数,此时是十进制整数的基数 */
#define MAX_SPACE 1000
typedef struct
... {
KeysType keys[MAX_NUM_OF_KEY]; /**//* 关键字 */
InfoType otheritems; /**//* 其它数据项 */
int next;
} SLCell; /**/ /* 静态链表的结点类型 */
typedef struct
... {
SLCell r[MAX_SPACE]; /**//* 静态链表的可利用空间,r[0]为头结点 */
int keynum; /**//* 记录的当前关键字个数 */
int recnum; /**//* 静态链表的当前长度 */
} SLList; /**/ /* 静态链表类型 */
typedef int ArrType[RADIX]; /**/ /* 指针数组类型 */
源文件:
/**/
/* alg10-11.c 链式基数排序 */
typedef int InfoType; /**/ /* 定义其它数据项的类型 */
typedef int KeyType; /**/ /* 定义RedType类型的关键字为整型 */
typedef struct
... {
KeyType key; /**//* 关键字项 */
InfoType otherinfo; /**//* 其它数据项 */
} RedType; /**/ /* 记录类型(同c10-1.h) */
typedef char KeysType; /**/ /* 定义关键字类型为字符型 */
#include " c1.h "
#include " c10-3.h "
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];
}
}
int ord( char c)
... { /**//* 返回k的映射(个位整数) */
return c-'0';
}
void Distribute(SLCell r[], int i,ArrType f,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]为各子表的尾指针。算法10.16 */
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]为头结点。算法10.17 */
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趟收集后: ",i+1);
printl(*L);
printf(" ");
}
}
void print(SLList L)
... { /**//* 按数组序号输出静态链表 */
int i,j;
printf("keynum=%d recnum=%d ",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=%d next=%d ",L.r[i].otheritems,L.r[i].next);
}
}
void Sort(SLList L, int adr[]) /**/ /* 改此句(类型) */
... { /**//* 求得adr[1..L.length],adr[i]为静态链表L的第i个最小记录的序号 */
int i=1,p=L.r[0].next;
while(p)
...{
adr[i++]=p;
p=L.r[p].next;
}
}
void Rearrange(SLList * L, int adr[]) /**/ /* 改此句(类型) */
... { /**//* adr给出静态链表L的有序次序,即L.r[adr[i]]是第i小的记录。 */
/**//* 本算法按adr重排L.r,使其有序。算法10.18(L的类型有变) */
int i,j,k;
for(i=1;i<(*L).recnum;++i) /**//* 改此句(类型) */
if(adr[i]!=i)
...{
j=i;
(*L).r[0]=(*L).r[i]; /**//* 暂存记录(*L).r[i] */
while(adr[j]!=i)
...{ /**//* 调整(*L).r[adr[j]]的记录到位直到adr[j]=i为止 */
k=adr[j];
(*L).r[j]=(*L).r[k];
adr[j]=j;
j=k; /**//* 记录按序到位 */
}
(*L).r[j]=(*L).r[0];
adr[j]=j;
}
}
#define N 10
void main()
... {
RedType d[N]=...{...{278,1},...{109,2},...{63,3},...{930,4},...{589,5},...{184,6},...{505,7},...{269,8},...{8,9},...{83,10}};
SLList l;
int *adr;
InitList(&l,d,N);
printf("排序前(next域还没赋值): ");
print(l);
RadixSort(&l);
printf("排序后(静态链表): ");
print(l);
adr=(int*)malloc((l.recnum)*sizeof(int));
Sort(l,adr);
Rearrange(&l,adr);
printf("排序后(重排记录): ");
print(l);
}
typedef int InfoType; /**/ /* 定义其它数据项的类型 */
typedef int KeyType; /**/ /* 定义RedType类型的关键字为整型 */
typedef struct
... {
KeyType key; /**//* 关键字项 */
InfoType otherinfo; /**//* 其它数据项 */
} RedType; /**/ /* 记录类型(同c10-1.h) */
typedef char KeysType; /**/ /* 定义关键字类型为字符型 */
#include " c1.h "
#include " c10-3.h "
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];
}
}
int ord( char c)
... { /**//* 返回k的映射(个位整数) */
return c-'0';
}
void Distribute(SLCell r[], int i,ArrType f,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]为各子表的尾指针。算法10.16 */
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]为头结点。算法10.17 */
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趟收集后: ",i+1);
printl(*L);
printf(" ");
}
}
void print(SLList L)
... { /**//* 按数组序号输出静态链表 */
int i,j;
printf("keynum=%d recnum=%d ",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=%d next=%d ",L.r[i].otheritems,L.r[i].next);
}
}
void Sort(SLList L, int adr[]) /**/ /* 改此句(类型) */
... { /**//* 求得adr[1..L.length],adr[i]为静态链表L的第i个最小记录的序号 */
int i=1,p=L.r[0].next;
while(p)
...{
adr[i++]=p;
p=L.r[p].next;
}
}
void Rearrange(SLList * L, int adr[]) /**/ /* 改此句(类型) */
... { /**//* adr给出静态链表L的有序次序,即L.r[adr[i]]是第i小的记录。 */
/**//* 本算法按adr重排L.r,使其有序。算法10.18(L的类型有变) */
int i,j,k;
for(i=1;i<(*L).recnum;++i) /**//* 改此句(类型) */
if(adr[i]!=i)
...{
j=i;
(*L).r[0]=(*L).r[i]; /**//* 暂存记录(*L).r[i] */
while(adr[j]!=i)
...{ /**//* 调整(*L).r[adr[j]]的记录到位直到adr[j]=i为止 */
k=adr[j];
(*L).r[j]=(*L).r[k];
adr[j]=j;
j=k; /**//* 记录按序到位 */
}
(*L).r[j]=(*L).r[0];
adr[j]=j;
}
}
#define N 10
void main()
... {
RedType d[N]=...{...{278,1},...{109,2},...{63,3},...{930,4},...{589,5},...{184,6},...{505,7},...{269,8},...{8,9},...{83,10}};
SLList l;
int *adr;
InitList(&l,d,N);
printf("排序前(next域还没赋值): ");
print(l);
RadixSort(&l);
printf("排序后(静态链表): ");
print(l);
adr=(int*)malloc((l.recnum)*sizeof(int));
Sort(l,adr);
Rearrange(&l,adr);
printf("排序后(重排记录): ");
print(l);
}
程序执行结果如下:
排序前(next域还没赋值):
keynum = 3 recnum = 10
keys = 278 otheritems = 1 next =- 858993460
keys = 109 otheritems = 2 next =- 858993460
keys = 063 otheritems = 3 next =- 858993460
keys = 930 otheritems = 4 next =- 858993460
keys = 589 otheritems = 5 next =- 858993460
keys = 184 otheritems = 6 next =- 858993460
keys = 505 otheritems = 7 next =- 858993460
keys = 269 otheritems = 8 next =- 858993460
keys = 008 otheritems = 9 next =- 858993460
keys = 083 otheritems = 10 next =- 858993460
第1趟收集后:
930 063 083 184 505 278 008 109 589 269
第2趟收集后:
505 008 109 930 063 269 278 083 184 589
第3趟收集后:
008 063 083 109 184 269 278 505 589 930
排序后(静态链表):
keynum = 3 recnum = 10
keys = 278 otheritems = 1 next = 7
keys = 109 otheritems = 2 next = 6
keys = 063 otheritems = 3 next = 10
keys = 930 otheritems = 4 next = 0
keys = 589 otheritems = 5 next = 4
keys = 184 otheritems = 6 next = 8
keys = 505 otheritems = 7 next = 5
keys = 269 otheritems = 8 next = 1
keys = 008 otheritems = 9 next = 3
keys = 083 otheritems = 10 next = 2
排序后(重排记录):
keynum = 3 recnum = 10
keys = 008 otheritems = 9 next = 3
keys = 063 otheritems = 3 next = 10
keys = 083 otheritems = 10 next = 2
keys = 109 otheritems = 2 next = 6
keys = 184 otheritems = 6 next = 8
keys = 269 otheritems = 8 next = 1
keys = 278 otheritems = 1 next = 7
keys = 505 otheritems = 7 next = 5
keys = 589 otheritems = 5 next = 4
keys = 930 otheritems = 4 next = 0
Press any key to continue
keynum = 3 recnum = 10
keys = 278 otheritems = 1 next =- 858993460
keys = 109 otheritems = 2 next =- 858993460
keys = 063 otheritems = 3 next =- 858993460
keys = 930 otheritems = 4 next =- 858993460
keys = 589 otheritems = 5 next =- 858993460
keys = 184 otheritems = 6 next =- 858993460
keys = 505 otheritems = 7 next =- 858993460
keys = 269 otheritems = 8 next =- 858993460
keys = 008 otheritems = 9 next =- 858993460
keys = 083 otheritems = 10 next =- 858993460
第1趟收集后:
930 063 083 184 505 278 008 109 589 269
第2趟收集后:
505 008 109 930 063 269 278 083 184 589
第3趟收集后:
008 063 083 109 184 269 278 505 589 930
排序后(静态链表):
keynum = 3 recnum = 10
keys = 278 otheritems = 1 next = 7
keys = 109 otheritems = 2 next = 6
keys = 063 otheritems = 3 next = 10
keys = 930 otheritems = 4 next = 0
keys = 589 otheritems = 5 next = 4
keys = 184 otheritems = 6 next = 8
keys = 505 otheritems = 7 next = 5
keys = 269 otheritems = 8 next = 1
keys = 008 otheritems = 9 next = 3
keys = 083 otheritems = 10 next = 2
排序后(重排记录):
keynum = 3 recnum = 10
keys = 008 otheritems = 9 next = 3
keys = 063 otheritems = 3 next = 10
keys = 083 otheritems = 10 next = 2
keys = 109 otheritems = 2 next = 6
keys = 184 otheritems = 6 next = 8
keys = 269 otheritems = 8 next = 1
keys = 278 otheritems = 1 next = 7
keys = 505 otheritems = 7 next = 5
keys = 589 otheritems = 5 next = 4
keys = 930 otheritems = 4 next = 0
Press any key to continue
算法的复杂度:O(n)。
程序参考:《《数据结构》算法实现及解析》。