基数排序(radix sort)属于“分配式排序”(distribution sort),又称“桶子法”(bucket sort)或bin sort,顾名思义,它是透过键值的部份资讯,将要排序的元素分配至某些“桶”中,藉以达到排序的作用,基数排序法是属于稳定性的排序,其时间复杂度为O (nlog(r)m),其中r为所采取的基数,而m为堆数,在某些时候,基数排序法的效率高于其它的稳定性排序法。
基数排序的实现虽然有很多,但是基本思想就是把元素从个位排好序,然后再从十位排好序,,,,一直到元素中最大数的最高位排好序,那么整个元素就排好序了。
比如:2,22,31,1221,90,85,105
个位排序:90,31,1221,2,22,85,105
十位排序:2,105,1221,22,31,85,90
百位排序:2,22,31,85,90,105,1221
千位排序:2,22,31,85,90,105,1221
注意:每次排序都是在上次排序的基础上进行排序的,也就是说此次排序的位数上他们相对时,就不移动元素(即顺序参数上一个位数的排序顺序)
1、把所有元素都分配到相应的桶中
2、把所有桶中的元素都集合起来放回到数组中
3、依次循环上面两步,循环次数为最大元素最高位数
参考下图
1、竖 0~9:表示桶个数(每个位数上的数字都在0到9之间);
2、行 0~length:0 表示在某个桶内有多少个元素;
3、比如:所有元素中个位为5的有两个元素,5 , 95;那么在下图中存放,分别是:(5,0) = 2;(5,1) = 5;(5,2)= 95;
#include<stdio.h> #include<stdlib.h> #define LEN 10 // 打印数组元素 void print_array(int *array, int length) { int index = 0; printf("array:\n"); for(; index < length; index++){ printf(" %d,", *(array+index)); } printf("\n\n"); } // 得到数组元素中最大数,并且计算其位数个数 void getPosCount(int *array, int length, int *posCount) { int max, index; for (max = *array, index = 0; index < length; index++){ if ( max < *(array + index)) max = *(array + index); } *posCount = 0; while(max){ max = max / 10; (*posCount)++; } } void radixSort(int *array, int length) { int* tmpArray[LEN];// 定义桶个数 0~9 共10个 int index, pos, posCount, element, elementNum, tmp, log = 1; for (element = 0; element < LEN; element++){// 每个桶最大能装length个元素,预防所有元素都是同一个数 tmpArray[element] = (int*)malloc((sizeof(int))*(length + 1)); tmpArray[element][0] = 0;// 初始化为0 } getPosCount(array, length, &posCount);// 把最高位数存放到posCount中 for (pos = 0; pos < posCount; pos++){// 从个位 ~ 十位 ~ 百位 。。。依次排序 for (element = 0; element < length; element++){// 把元素放到桶里 分配动作 tmp = ++tmpArray[ (array[element] / log ) % 10][0]; tmpArray[ (array[element] / log) % 10][tmp] = array[element]; } for (index = 0, element = 0; (element < LEN) && (index < length); element++){ for (elementNum = 1; elementNum <= tmpArray[element][0]; elementNum++) array[index++] = tmpArray[element][elementNum]; tmpArray[element][0] = 0; } log = log * 10; } } int main(void) { int array[] = {2, 5, 337, 24, 10000, 5, 30, 123, 3, 9, 100, 1}; //int array[] = {2, 5, 3, 4, 1, 5, 0, 2, 3, 9, 1, 7, 8, 6}; //int array[] = {2, 5, 3, 4, 1, 5, 5, 55555, 9, 5, 7, 5, 6}; int length = (sizeof(array)) / (sizeof(array[1])); print_array(array, length); radixSort(array, length); print_array(array, length); return 0; }
运行结果:
#include<stdio.h> #include<stdlib.h> void print_array(int *array, int length) { int index = 0; printf("array:\n"); for(; index < length; index++){ printf(" %d,", *(array+index)); } printf("\n\n"); } void getCount(int *array, int length, int *count) { int max, index; for (max = *array, index = 0; index < length; index++){ if ( max < *(array + index)) max = *(array + index); } *count = 0; while(max){ max = max / 10; (*count)++; } } void radixSort(int *array, int length) { int *tmpArray = (int*)malloc(sizeof(int)*(10)); int tmp[length]; int i, j, count, log = 1; getCount(array, length, &count); for (j = 0; j < count; j++){ // 循环最大位数次 for (i = 0; i < 10; i++)tmpArray[i] = 0;// 初始化数组 for (i = 0; i < length; i++) tmpArray[ (array[i] / log) % 10 ]++;// 元素值对应桶标记 for (i = 1; i <= 10; i++) tmpArray[i] += tmpArray[i-1];// 统计大于各元素的个数 for (i = length - 1; i >= 0; i--){ // 按照指定位数对元素进行排序 tmp[tmpArray[ (array[i] / log) % 10] - 1] = array[i]; tmpArray[ (array[i] / log) % 10 ]--; } for (i = 0; i < length; i++) array[i] = tmp[i];// 把排序好的元素放回到元素数组中 log = log * 10; } free(tmpArray);// 释放内存 } int main(void) { //int array[] = {2, 5, 337, 24, 10000, 5, 30, 123, 3, 9, 100, 1}; int array[] = {2, 5, 3, 4, 1, 5, 0, 2, 3, 9, 1, 7, 8, 6}; int length = (sizeof(array)) / (sizeof(array[1])); print_array(array, length); radixSort(array, length); print_array(array, length); return 0; }
运行结果:
这个时间复杂度比较好计算:count * length;其中 count 为数组元素最高位数,length为元素个数;所以时间复杂度:O( k*n )
空间复杂度是使用了两个临时的数组:10 + length;所以空间复杂度:O(n)