基数排序(radix sorting)属于“分配式排序”(distribution sort),又称“桶子法”(bucket sort)的稳定性排序法。基数排序的方式可以采用最低有效位LSD(Least significant digital)或最高有效位MSD(Most significant digital)。LSD的排序方式将所有待比较数值统一为同样的数位长度,数位较短的数前面补零。 然后 从最低位开始,依次进行一次排序。这样从最低位排序一直到最高位排序完成以后, 数列就变成一个有序序列。而MSD则相反,由最高位开始,先按最高位排序分组,同一组中记录,最高位相等,再对各组按次高位排序分成子组,之后,对后面的位继续这样的排序分组,直到各子组排序完成。再将各组连接起来,便得到一个有序序列。下面以一组数为例:{90,100,204,20,32,19,56,48,3,91,94,90},采用LSD方式:
0 90 100 20 90 0 100 3(3在排序前要填充为003)204
1 91 1
2 32 2 20
3 3 按最低位排序结果{90 100 20 90 91 32 3 204 94 56 48} 3 32 得到第二次排序结果{100 3 204 20 32 48 56 90 90 91 94}
4 204 94 -------------》 4 48 -------------------》
5 5 56
6 56 6
7 7
8 48 8
9 9 90 90 91 94
----------------------------------------------------------------------------------------------------------------------------------------------------------
0 3 20 32 48 56 90 90 91 94 {用0填充了最高位)
1 100
2 204
3 第三次排序结束(最高有3位数)
4 ---------------------------------> {3 20 32 48 56 90 90 91 94 100 204} 有序序列
5
6
7
8
9
LSD的基数排序适用于位数小的数列,如果位数多的话,使用MSD的效率会比较好。MSD的方式与LSD相反,是由高位数为基底开始进行分配,但在分配之后并不马上合并回一个数组中,而是在每个“桶子”中建立“子桶”,将每个桶子中的数值按照下一数位的值分配到“子桶”中。在进行完最低位数的分配后再合并回单一的数组中,下一篇博客会介绍。
C语言实现:(代码来自互联网)
#include<stdio.h> #include<stdlib.h> int maxbit(int data[], int n) //辅助函数,求数据的最大位数 {int d = 1; //保存最大的位数int p = 10;for(int i = 0; i < n; ++i) {while(data[i] >= p) {p *= 10;++d;}}return d; } void radixsort(int data[], int n) //基数排序 {int d = maxbit(data, n); //数组中的元素的最大位数int *tmp = (int *)malloc(n * sizeof(int));int *count = (int *)malloc(10 * sizeof(int)); //计数器int i, j, k;int radix = 1;for(i = 1; i <= d; i++) { //进行d次排序for(j = 0; j < 10; j++)count[j] = 0; //每次分配前清空计数器for(j = 0; j < n; j++) {k = (data[j] / radix) % 10; //计算每次循环某一位的数字count[k]++; //统计每个桶中的记录数}for(j = 1; j < 10; j++)count[j] = count[j - 1] + count[j]; //第j个桶以及之前所有桶中元素的总数for(j = n - 1; j >= 0; j--) { //将所有桶中记录依次收集到tmp中k = (data[j] / radix) % 10;tmp[count[k] - 1] = data[j];count[k]--;}for(j = 0; j < n; j++) //将临时数组的内容复制到data中data[j] = tmp[j];radix = radix * 10;}free(tmp);free(count); } int main() {int a[] = { 90,100,204,20,32,19,56,48,3,91,94,90};int n;n = sizeof(a) / sizeof(a[0]);radixsort(a, n);for(int k = 0; k < n; k++)printf("%d ", a[k]);printf("\n");return 0; }时间效率:设待排序列为n个记录,d个关键码,关键码的取值范围为radix,则进行链式基数排序的时间复杂度为O(d(n+radix)),其中,一趟分配时间复杂度为O(n),一趟收集时间复杂度为O(radix),共进行d趟分配和收集。 空间效率:需要2*radix个指向队列的辅助空间,以及用于静态链表的n个指针。