基数排序(Radix Sort)
基数排序(radix sort)属于“分配式排序”(distribution sort),又称“桶子法”(bucket sort)或bin sort,顾名思义,它是透过键值的部份资讯,将要排序的元素分配至某些“桶”中,以达到排序的作用。
1. 基本思想
“分配”和“收集”。
在计数排序中,当k很大时,时间和空间的开销都会增大(当待排序序列为 { 8888, 1234, 9999 },用计数排序,此时不但浪费很多空间,而且时间方面还不如比较排序)。于是把待排序记录分解成个位(第一位)、十位(第二位)……然后分别以第一位、第二位……对整个序列进行计数排序。这样的话分解出来的每一位不超过9,即用计数排序序列中最大值是9。
多关键码排序按照从最主位关键码到最次位关键码或从最次位到最主位关键码的顺序逐次排序,分两种方法:
最高位优先(Most Significant Digit first)法,简称MSD法:先按k1排序分组,同一组中记录,关键码k1相等,再对各组按k2排序分成子组,之后,对后面的关键码继续这样的排序分组,直到按最次位关键码kd对各子组排序后。再将各组连接起来,便得到一个有序序列。
最低位优先(Least Significant Digit first)法,简称LSD法:先从kd开始排序,再对kd-1进行排序,依次重复,直到对k1排序后便得到一个有序序列。
2. 排序流程
(1)以LSD为例,假设待排序序列为 {73, 22, 93, 43, 55, 14, 28, 65, 39, 81};
(2)根据个位数的数值,在走访数值时将它们分配至编号0到9的桶中;
(3)将这些桶子中的数值重新串接起来,成为新的序列,接着再进行一次分配,这次是根据十位数来分配。
(4)将这些桶子中的数值重新串接起来,此时排序完成。
如果排序的对象有三位数以上,则持续进行以上的动作直至最高位数为止。
3. 算法实现
例1. 两位数排序
代码
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
/* 序列中记录个数 */
#define N 10
/* 序列中最大值,用于计数数组大小 */
#define MAXRADIX 2
/* 分配的桶大小 */
#define MAX 9
int array[N]={
73, 22, 93, 43, 55, 14, 28, 65, 39, 81};
/* 打印数组 */
void print_array(int arr[],int len)
{
int i;
for(i=0;i<len;i++)
printf("%2d ",arr[i]);
printf("\n");
}
/* 获取关键字 */
inline int get_radix(int value,int radix)
{
int i,n=1;
for(i=0;i<radix;i++) n*=10;
return ((value / n) % 10);
}
/* 函数功能:计数排序
* 参数:arr为待排序序列;len为序列长度;max为序列中最大值;radix关键字
*/
void counting_sort(int arr[], int len, int max, int radix)
{
int i,r;
int *count=(int *)malloc(sizeof(int)*(max+1)); /* 计数数组[0,max] 大小max+1 */
int *tmp=(int *)malloc(sizeof(int)*len); /* 计数完成后输出到临时数组 */
/* 初始化计数值 */
for(i=0;i<=max;i++)
count[i]=0;
/* 计算等于a[i]的记录个数 */
printf("Allocate:\t");
for(i=0;i<len;i++)
{
r=get_radix(arr[i],radix);
printf("[%d-%d] ",arr[i],r);
count[r]++;
}
printf("\n");
printf("Count:\t");
print_array(count,max+1);
/* 计算小于等于a[i]的记录个数 */
for(i=1;i<=max;i++)
count[i]+=count[i-1<