任何只使用比较的一般排序算法在最坏情况下需要运行时间Ω(NlogN),但在某些特殊情况下,以线性时间进行排序仍然是可能的。此处的基数排序便是一个很好的例子。
基数排序为桶式排序的推广,即按照次位优先的原则对数据进行多趟桶式排序。
以数组{8, 20, 59, 30, 21, 40, 10, 11, 22, 34, 23, 5, 33, 65, 44, 75, 17, 66, 77, 88, 99, 9}为例,对其进行基数排序:
显然需要两趟桶式排序。
第一趟结果:
第二趟结果:
至此,算法得出正确结果。
该排序算法的时间复杂度为O(P(N+B)),其中,P为排序的趟数,N为待排序元素的个数,B为桶数。
鉴于本人还比较菜,写出的代码着实比较……丑陋。。。不过凑合着也还是可以得到正确结果的。(此算法看起来好像比别的排序算法友善许多,实现起来着实挺狗屎的,算了是我太菜了……)
#include<stdio.h>
#include<stdlib.h>
#define B 10 //B为基数排序设定的基数
struct list {
int index;
struct list* next;
};
int getDigitNum(int a[], int n) //获取数组最大元素的位数,即为排序的趟数
{
int max = a[0];
int num = 0;
for (int i = 0; i < n; i++) {
if (max < a[i])
max = a[i];
}
while (max) {
max = max / B;
num++;
}
return num;
}
int getNumInPos(int num, int pos) //获取num从低位到高位第pos位的数
{
int temp = 1;
for (int i = 0; i < pos - 1; i++)
temp *= B;
return (num / temp) % B;
}
void radixSort(int a[], int n) {
int N = getDigitNum(a, n);
int c;
struct list Count[B] ; //定义结构体数组,存放表头
struct list* ptr,*tmp;
ptr = (struct list*)malloc(sizeof(struct list));
tmp = (struct list*)malloc(sizeof(struct list));
for (int i = 1; i <= N; i++)
{
for (int j = 0; j < B; j++) //结构体数组初始化,每趟排序后重新初始化,丢掉上一趟的数据
{
Count[j].index = j;
Count[j].next = NULL;
}
for (int j = 0; j < n; j++) //数据依此放入桶中
{
c = getNumInPos(a[j], i);
if (!Count[c].next)
{
tmp = (struct list*)malloc(sizeof(struct list)); //tmp的值每次使用需更新
tmp->index = a[j];
tmp->next = NULL;
Count[c].next = tmp;
}
else
{
ptr = Count[c].next;
while (ptr->next)
ptr = ptr->next;
tmp = (struct list*)malloc(sizeof(struct list));
tmp->index = a[j];
tmp->next = NULL;
ptr->next = tmp;
}
}
int k = 0;
for (int j = 0; j < B; j++) //将放入桶中的数据按顺序收集入原数组
{
ptr = Count[j].next;
while (ptr)
{
a[k++] = ptr->index;
ptr = ptr->next;
}
}
}
}
int main() {
int array[10] = { 85, 666, 99, 13, 4, 0, 756, 9, 208, 139 };
printf("排序前:\n");
for (int i = 0; i < 10; i++) {
printf("%d ", array[i]);
}
radixSort(array, 10);
printf("\n排序后:\n");
for (int i = 0; i < 10; i++) {
printf("%d ", array[i]);
}
return 0;
}