基数排序属于“分配式排序”(distribution sort),基数排序法又称“桶子法”(bucket sort)或bin sort,顾名思义,它是透过键值的部份资讯,将要排序的元素分配至某些“桶”中,藉以达到排序的作用,基数排序法是属于稳定性的排序。
时间效率:设待排序列为n个记录,d个关键码,关键码的取值范围为radix,则进行链式基数排序的 时间复杂度为O(d(n+radix)),其中,一趟分配时间复杂度为O(n),一趟收集时间复杂度为O(radix),共进行d趟分配和收集。空间效率:需要2*radix个指向队列的辅助空间,以及用于静态链表的n个指针。
最高位优先(Most Significant Digit first)法,简称MSD法:先按k1排序分组,同一组中记录,关键码k1相等,再对各组按k2排序分成子组,之后,对后面的关键码继续这样的排序分组,直到按最次位关键码kd对各子组排序后。再将各组连接起来,便得到一个有序序列。
最低位优先(Least Significant Digit first)法,简称LSD法:先从kd开始排序,再对kd-1进行排序,依次重复,直到对k1排序后便得到一个有序序列。
下面是C语言实现的一个例子(使用最低优先法)
#include <unistd.h>
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#define RADIX 10 //基数
#define KEY_SIZE 6 //键的最大个数
#define LIST_SIZE 20 //需要排序数的个数
typedef struct
{
int key;
int next; //静态链域
} RecordType1;
typedef struct
{
RecordType1 r[LIST_SIZE + 1];
int length;
int keynum;
} SLinkList; //静态链表
typedef int PVector[RADIX];
int num[LIST_SIZE][KEY_SIZE]; //将整数进行分离
/*将输入的十进制数的每一位拆分开来*/
void Order(SLinkList *s_num)
{
int i, m, j, tmp;
int r_num;
m = s_num->keynum;
for (i = 1; i <= s_num->length; i++)
{
r_num = s_num->r[i].key;
for (j = m-1; j >= 0; j--)
{
tmp = r_num % 10;
num[i][j] = tmp;
r_num = r_num / 10;
while (r_num == 0 && j != 0)
{
j--;
num[i][j] = 0;
break;
}
}
}
}
/*分配*/
void Distribute(SLinkList *s_num, int i, PVector head, PVector tail)
{
int j, p;
for (j = 0; j <= RADIX-1; ++j)
{
head[j] = 0;
}
p = s_num->r[0].next;
while(p != 0)
{
j = num[p][i];
if (head[j] == 0)
head[j] = p;
else
s_num->r[tail[j]].next = p;
tail[j] = p;
p = s_num->r[p].next;
}
}
/*回收*/
void Collect(SLinkList *s_num, PVector head, PVector tail)
{
int j, t;
j = 0;
while (head[j] == 0)
++j;
s_num->r[0].next = head[j];
t = tail[j];
while (j < RADIX - 1)
{
++j;
while ((j < RADIX - 1) && (head[j] == 0))
{
++j;
}
if (head[j] != 0)
{
s_num->r[t].next = head[j];
t = tail[j];
}
}
s_num->r[t].next = 0;
}
//找最大数
int maxNum(SLinkList *s_num)
{
int i, max = 0;
for (i = 1; i <= s_num->length; i++)
{
if (s_num->r[i].key > max)
max = s_num->r[i].key;
}
return max;
}
/*确定关键字的个数(找最大数关键子的位数)*/
void Keynum(SLinkList *s_num)
{
int max_num, temp = 0, count = 1;
max_num = maxNum(s_num); //找最大数
temp = max_num / 10;
while (temp != 0)
{
count++;
temp = temp / 10;
}
s_num->keynum = count;
}
/*基数排序*/
void RadixSort(SLinkList *s_num)
{
PVector head, tail;
int i, d, n;
n = s_num->length;
for (i = 0; i <= n-1; ++i)
s_num->r[i].next = i+1;
s_num->r[n].next = 0;
d = s_num->keynum; //关键字的个数
for (i = d-1; i >= 0; i--)
{
Distribute(s_num, i, head, tail); //第i趟分配
Collect(s_num, head, tail); //第i趟回收
}
}
/*输出排序后的结果*/
void Print(SLinkList *s_num)
{
int j;
j = s_num->r[0].next;
printf("\nsort finish:");
while (j != 0)
{
printf("%d ", s_num->r[j].key);
j = s_num->r[j].next;
}
printf("\n");
}
int main(int argc, char *argv[])
{
SLinkList *s_num;
int i;
s_num = (SLinkList *)malloc(sizeof(SLinkList));
printf("input sort count is : ");
scanf("%d", &s_num->length);
printf("\nPlease input sort number is :");
for (i = 1; i <= s_num->length; i++)
{
scanf("%d", &s_num->r[i].key);
}
Keynum(s_num); //计算关键字的个数
Order(s_num); //将输入的十进制数进行拆分
RadixSort(s_num);
Print(s_num);
return EXIT_SUCCESS;
}