桶排序
在谈到基数排序之前我想先说一下桶排序,因为基数排序是桶排序的推广。
桶排序——最快最简单的排序
桶排序:
假设你要排序的数是0~N,那么你需要开辟一个大小为N的数组num,并且将此数组中所有元素初始化为0,接下来请遍历你想要排序的数,将num数组对应下标等于序列中的数字的元素加1,最后你只需要遍历num数组,假如num[i]=n,那么你只需要将i打印n次即可。
下面是桶排序的示例:
int *bucket_sort(const int a[], int len)
{
int num[1000];
for (int i = 0; i < 1000; i++)
num[i] = 0;
for (int i = 0; i < len; i++) {
num[a[i]]++;
}
int *p = num;
return p;
}
至此,桶排序的优缺点我们其实已经一目了然了
优点:简单明了,易于思考,最快最简单的排序
缺点:太过于浪费空间了,比如你想要排列0,1,3,2,5,99999,很明显,按照上述的方法你需要开辟99999这么大的一个数组,显然这是不现实且没有必要的浪费空间的行为。
那么,为了解决这个问题,便有了基数排序。
基数排序
基数排序是桶排序的推广,假设我们有10个数需要排序,这10个数的范围在0~999之间,我们将其排序,999还好,但是如果是9999999呢?显然我们是不能够使用桶排序的,那样是不现实的。
我们的策略是:多趟桶排序即基数排序,基数排序分为最低位优先基数排序(LSD)和最高位优先基数排序(MSD),在这里我将就低位基数排序来谈基数排序,高位基数排序同理。
下面例子说明10个数的基数排序的具体做法,假设输入为,64,8,216,512,27,729,0,1,343,125.
第一趟桶排序的结果(个位桶排序)
第二趟桶排序的结果(十位桶排序)
第三趟桶排序的结果(百位桶排序)
为了使得算法得出正确的结果,要注意唯一可能出错的地方就是如果两个数出自同一个桶中但顺序却是错误的,不过,只要我们保证前面各趟排序当几个数进入同一个桶时,它们是以排序好的顺序状态进入的即可。
下面的例子是我基于链表实现的,这个实现个人觉得并不是比较好,后续我将会更改为更加巧妙的实现方法。
#ifndef RADIX_H
#define RADIX_H
#define NUM_LEN 10
typedef struct value {
int bucket_num;
int num[NUM_LEN];
int numi;
} value_t;
typedef struct node {
value_t *value;
struct node *next;
} node_t;
int *radix_sort(int a[], int len);
#endif
#include "radix.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define NUM_LEN 10
node_t *create_bucket()
{
node_t *dummy = (node_t *)malloc(sizeof(node_t));
node_t *tmp = dummy;
int loop = 10, i = 0;
while (loop--) {
node_t *node = (node_t *)malloc(sizeof(node_t));
node->value = (value_t *)malloc(sizeof(value_t));
tmp->next = node;
tmp = node;
node->value->numi = 0;
node->value->bucket_num = i;
i++;
for (int j = 0; j < NUM_LEN; j++) {
node->value->num[j] = 0;
}
}
tmp->next = NULL;
return dummy;
}
void read_clear_bucket(int a[], node_t *h)
{
int j = 0;
node_t *tmp = h->next;
while (tmp != NULL) {
for (int i = 0; i < tmp->value->numi; i++) {
a[j++] = tmp->value->num[i];
tmp->value->num[i] = 0;
}
tmp->value->numi = 0;
tmp = tmp->next;
}
}
int *radix_sort(int a[], int len)
{
node_t *h = create_bucket();
int li = 0;
node_t *tmp = h->next;
for (int i = 0; i < len; i++) {
tmp = h->next;
if (a[i] >= 0 && a[i] < 10) {
li = a[i];
} else if (a[i] >= 10 && a[i] < 100) {
li = a[i]%10;
} else if (a[i] >= 100 && a[i] < 1000) {
li = a[i]%10;
}
while (li != tmp->value->bucket_num) {
tmp = tmp->next;
}
tmp->value->num[tmp->value->numi] = a[i];
tmp->value->numi++;
}
read_clear_bucket(a, h);
//---------------------------------------------------------------------------------------
for (int i = 0; i < len; i++) {
tmp = h->next;
if (a[i] >= 0 && a[i] < 10) {
li = 0;
} else if (a[i] >= 10 && a[i] < 100) {
li = a[i]/10;
} else if (a[i] >= 100 && a[i] < 1000) {
li = a[i]%100/10;
}
while (li != tmp->value->bucket_num) {
tmp = tmp->next;
}
tmp->value->num[tmp->value->numi] = a[i];
tmp->value->numi++;
}
read_clear_bucket(a, h);
//--------------------------------------------------------------------------------------
for (int i = 0; i < len; i++) {
tmp = h->next;
if (a[i] >= 0 && a[i] < 10) {
li = 0;
} else if (a[i] >= 10 && a[i] < 100) {
li = 0;
} else if (a[i] >= 100 && a[i] < 1000) {
li = a[i]/100;
}
while (li != tmp->value->bucket_num) {
tmp = tmp->next;
}
tmp->value->num[tmp->value->numi] = a[i];
tmp->value->numi++;
}
read_clear_bucket(a, h);
return a;
}
参考文献:《数据结构与算法——C语言描述》