基数排序(radix sort)属于“分配式排序”(distribution sort),又称“桶子法”(bucket sort)或bin sort,顾名思义,它是透过键值的部份资讯,将要排序的元素分配至某些“桶”中,藉以达到排序的作用,基数排序法是属于稳定性的排序,其时间复杂度为O (nlog(r)m),其中r为所采取的基数,而m为堆数,在某些时候,基数排序法的效率高于其它的稳定性排序法。
实现方法:
最高位优先(Most Significant Digit first)法,简称MSD法:先按k1排序分组,同一组中记录,关键码k1相等,再对各组按k2排序分成子组,之后,对后面的关键码继续这样的排序分组,直到按最次位关键码kd对各子组排序后。再将各组连接起来,便得到一个有序序列。
最低位优先(Least Significant Digit first)法,简称LSD法:先从kd开始排序,再对kd-1进行排序,依次重复,直到对k1排序后便得到一个有序序列。
(1)假设有欲排数据序列如下所示:
73 22 93 43 55 14 28 65 39 81首先根据个位数的数值,在遍历数据时将它们各自分配到编号0至9的桶(个位数值与桶号一一对应)中。
73 22 93 43 55 14 28 65 39 81首先根据个位数的数值,在遍历数据时将它们各自分配到编号0至9的桶(个位数值与桶号一一对应)中。
分配结果(逻辑想象)如下图所示:
分配结束后。接下来将所有桶中所盛数据按照桶号由小到大(桶中由顶至底)依次重新收集串起来,得到如下仍然无序的数据序列:
81 22 73 93 43 14 55 65 28 39
接着,再进行一次分配,这次根据十位数值来分配(原理同上),分配结果(逻辑想象)如下图所示:
81 22 73 93 43 14 55 65 28 39
接着,再进行一次分配,这次根据十位数值来分配(原理同上),分配结果(逻辑想象)如下图所示:
代码:
C:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 |
#include<math.h> testBS() { inta[] = {2, 343, 342, 1, 123, 43, 4343, 433, 687, 654, 3}; int *a_p = a; //计算数组长度 intsize = sizeof(a) / sizeof(int); //基数排序 bucketSort3(a_p, size); //打印排序后结果 inti; for(i = 0; i < size; i++) { printf("%d\n", a[i]); } intt; scanf("%d", t); } //基数排序 voidbucketSort3(int *p, intn) { //获取数组中的最大数 intmaxNum = findMaxNum(p, n); //获取最大数的位数,次数也是再分配的次数。 intloopTimes = getLoopTimes(maxNum); inti; //对每一位进行桶分配 for(i = 1; i <= loopTimes; i++) { sort2(p, n, i); } } //获取数字的位数 intgetLoopTimes(intnum) { intcount = 1; inttemp = num / 10; while(temp != 0) { count++; temp = temp / 10; } returncount; } //查询数组中的最大数 intfindMaxNum(int *p, intn) { inti; intmax = 0; for(i = 0; i < n; i++) { if(*(p + i) > max) { max = *(p + i); } } returnmax; } //将数字分配到各自的桶中,然后按照桶的顺序输出排序结果 voidsort2(int *p, intn, intloop) { //建立一组桶此处的20是预设的根据实际数情况修改 intbuckets[10][20] = {}; //求桶的index的除数 //如798个位桶index=(798/1)%10=8 //十位桶index=(798/10)%10=9 //百位桶index=(798/100)%10=7 //tempNum为上式中的1、10、100 inttempNum = (int)pow(10, loop - 1); inti, j; for(i = 0; i < n; i++) { introw_index = (*(p + i) / tempNum) % 10; for(j = 0; j < 20; j++) { if(buckets[row_index][j] == NULL) { buckets[row_index][j] = *(p + i); break; } } } //将桶中的数,倒回到原有数组中 intk = 0; for(i = 0; i < 10; i++) { for(j = 0; j < 20; j++) { if(buckets[i][j] != NULL) { *(p + k) = buckets[i][j]; buckets[i][j] = NULL; k++; } } } } |
C++:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
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 = newint[n]; int *count = newint[10]; //计数器 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]; //将tmp中的位置依次分配给每个桶 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; } delete[]tmp; delete[]count; } |