基数排序介绍
基数排序是桶排序的扩展,它的基本思想是:将整数按位数切割成不同的数字,然后按每个位数分别比较。
具体做法是:
将所有待比较数值统一为同样的数位长度,数位较短的数前面补零。然后,从最低位开始,依次进行一次排序。这样从最低位排序一直到最高位排序完成以后, 数列就变成一个有序序列。
基数排序图文说明
通过基数排序对数组{53, 542, 3, 63, 14, 214, 154, 748, 616},它的示意图如下:
在上图中,首先将所有待比较数值统一为统一位数长度,接着从最低位开始,依次进行排序。
1. 按照个位数进行排序。
2. 按照十位数进行排序。
3. 按照百位数进行排序。
排序后,数列就变成了一个有序序列。
/**
* 实验题目:
* 实现基数排序算法
* 实验目的:
* 领会基数排序的过程和算法设计
* 实验内容:
* 设计程序,实现基数排序算法。用相关数据进行测试,并
* 输出各趟的排序结果。
* 基数排序基本思想:
* 将整数按位数切割成不同的数字,然后按每个位数分别比较。
* 基数排序具体做法:
* 将所有待比较数值统一为同样的数位长度,数位较短的数前面
* 补零。然后,从最低位开始,依次进行一次排序。这样从最低位排
* 序一直到最高位排序完成以后, 数列就变成一个有序序列。
* 备注:
* 这里基数排序的关键字为整数,采用从低位到高位即最低位优先
* 的排序方式。排序数据采用不带头结点的单链表存放。
*/
#include
#include
#define MAXE (20) // 线性表中最多元素个数
#define MAXR (10) // 基数的最大取值
typedef struct node
{
int key; // 记录的关键字
struct node *next;
}node_type; // 单链表的结点类型
/*-----------采用尾插法由a[0..n-1]创建首结点指针为p的单链表-------------*/
static void create_link(node_type *&p, int a[], int n) // 指针的引用
{
node_type *s, *t;
for(int i = 0; i < n; i++)
{
s = (node_type *)malloc(sizeof(node_type));
s->key = a[i];
if(i == 0)
{
p = s;
t = s;
}
else
{
t->next = s;
t = s;
}
}
t->next = NULL; // 尾结点的next域置NULL
}
/*-----------输出单链表-------------*/
static void disp_link(node_type *p)
{
while(p != NULL)
{
printf("%4d", p->key);
p = p->next;
}
printf("\n");
}
/*-----------销毁单链表-------------*/
static void destroy_link(node_type *p)
{
node_type *pre = p;
node_type *q = pre->next;
while(q != NULL)
{
free(pre);
pre = q;
q = q->next;
}
free(pre);
}
/*-----------对于数值num,从低位到高位,取第i位的数字-------------*/
static int keyi(int num, int i)
{
int j;
for(j = 0; j < i; j++)
num = num / 10;
return num % 10;
}
/**
* 功能:
* 实现最低位优先的基数排序
* 参数:
* p指向单链表的首结点
* r为基数
* d为关键字位数
*/
static void radix_sort(node_type *&p, int r, int d) // 指针的引用
{
node_type *head[MAXR], *tail[MAXR], *t; // 定义各链队的首尾指针
int i, j, k;
for(i = 0; i < d; i++) // 从低位到高位循环
{
for(j = 0; j < r; j++) // 初始化各链队首、尾指针
head[j] = tail[j] = NULL;
while(p != NULL) // 对于原链表中每个结点循环
{
k = keyi(p->key, i); // 找p结点关键字的第i位k
printf("第%d位为%d\n", i + 1, k);
if(head[k] == NULL) // 将p结点分配到第k个链队
{
head[k] = p;
tail[k] = p;
}
else
{
tail[k]->next = p;
tail[k] = p;
}
p = p->next; // 继续扫描下一个结点
}
p = NULL;
for(j = 0; j < r; j++) // 对于每一个链队循环
{
if(head[j] != NULL) // 进行收集
{
if(p == NULL)
{
p = head[j];
t = tail[j];
}
else
{
t->next = head[j];
t = tail[j];
}
}
}
t->next = NULL;
printf("按%d位排序:", i + 1);
disp_link(p);
}
}
int main(int argc, char *argv[])
{
int n = 10;
node_type *p;
int a[] = {75, 223, 98, 44, 157, 2, 29, 164, 38, 82};
create_link(p, a, n);
printf(" 排序前:");
disp_link(p);
radix_sort(p, 10, 3);
printf(" 排序后:");
disp_link(p);
destroy_link(p);
return 0;
}
测试结果:
排序前: 75 223 98 44 157 2 29 164 38 82
第1位为5
第1位为3
第1位为8
第1位为4
第1位为7
第1位为2
第1位为9
第1位为4
第1位为8
第1位为2
按1位排序: 2 82 223 44 164 75 157 98 38 29
第2位为0
第2位为8
第2位为2
第2位为4
第2位为6
第2位为7
第2位为5
第2位为9
第2位为3
第2位为2
按2位排序: 2 223 29 38 44 157 164 75 82 98
第3位为0
第3位为2
第3位为0
第3位为0
第3位为0
第3位为1
第3位为1
第3位为0
第3位为0
第3位为0
按3位排序: 2 29 38 44 75 82 98 157 164 223
排序后: 2 29 38 44 75 82 98 157 164 223