基数排序是桶式排序的推广。——《数据结构与算法分析:C语言描述》
假设我们有10个数,范围在0-999之间,我们要将其排序。显然,我们不能使用桶式排序,考虑最坏的情况下我们将需要使用1000个桶,这样桶就太多了。我们的策略是使用多趟桶式排序(对于十进制数来说,其基数为10,对每位(个、十、百)进行桶式排序最多只需要10个桶)。我们用最低有效位(LSB)优先的方式进行桶式排序,也就是说首先对这10个数按照个位上的数字进行一次桶式排序,再对这10个数按照十位上的数字进行一次桶式排序,最后对这10个数按照百位上的数字进行一次桶式排序。这样经过三趟桶式排序后,这10个数也就排好序了。(注:对于一位数,其十位、百位均为0;对于两位数,其百位为0)
假设10个数为:64、8、216、512、27、729、0、1、343、125,为方便起见我们将不足三位的数以高位补零的方式全部补为三位数。
高位补零后这10个数为:064、008、216、512、027、729、000、001、343、125.
第一趟桶式排序(个位):
000 | 001 | 512 | 343 | 064 | 125 | 216 | 027 | 008 | 729 |
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
第二趟桶式排序(十位):
008 001 000 |
216 512 |
729 027 125 |
343 |
064 |
|||||
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
第三趟桶式排序(百位):
064 027 008 001 000 |
125 |
216 |
343 |
512 |
729 |
||||
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
我们已知桶式排序的时间复杂度为O(N+B),其中N为待排序元素个数,而B是桶数。我们又知道基数排序是以多趟桶式排序来实现的,所以基数排序的运行时间是O(P(N+B)),其中P是排序的趟数。
#include "list.h" #include <stdio.h> #include <stdlib.h> #include <math.h> void radix_sort(int A[], int N, int M) /* A[]为待排序数组,N为数组A中元素个数,M为数组A中最大值的位数 */ { /* 假设待排序的数全部是正整数 */ int i, j, k, l, m, n; list bucket[10]; ptr_to_node ptr; for(k = 0; k < 10; k++) bucket[k] = create_list(); /* 分配10个桶(链表) */ for(i = 0; i < M; i++) /* i=0(按个位上的数字排序);i=1(按十位上的数字排序)… */ { l = 0; for(j = 0; j < N; j++) { n = A[j] / pow(10, i) ; m = n % 10; insert_to_tail(A[j], bucket[m]); /* 按位(个、十、百…)排序,放入对应的桶中 */ } for(k = 0; k < 10; k++) { ptr = bucket[k]->next; while(ptr != NULL) { A[l] = ptr->data; /* 把本次(比如按照个位数排序)排序后的数按照顺序重新装入数组A,以待下次(按照下个数位的)桶排序使用 */ l++; ptr = ptr->next; } //bucket[k]->next = NULL; make_empty(bucket[k]); /* 把桶置空,为下一个数位排序做准备,可以用bucket[k]->next = NULL;实现此语句的功能,但未释放资源 */ } } } int main(void) { int i; int A[] = {64, 8, 216, 512, 27, 729, 0, 1, 343, 125}; printf("unsorted: "); for(i = 0; i < 10; i++) printf("%d ", A[i]); printf("\n"); radix_sort(A, 10, 3); printf("sorted : "); for(i = 0; i < 10; i++) printf("%d ", A[i]); printf("\n"); }
其中list.c和list.h源码参考:http://www.cnblogs.com/nufangrensheng/p/3579993.html。
编译运行结果如下: