链式基数排序
链式基数排序
基本策略
- 分配----收集
何为链式基数排序?
- 将单关键字排序转成多关建字排序,具体为,在排序过程中,将关键字拆分成若干项,然后把每一项作为一个“关键字“。
- 对于整数或字符串型的关键字,可将其拆分为单个数字或单个字母。
- 例如:当单关键字“ 123 ”,从低位到高位可拆成关键字 “3”,“2”,“1”
基本思想
- 从最低位的关键字开始,按关键字的不同值将序列中的数据分配到不同的队列中
- 然后按关键字从小到大(升序)收集起来,此时完成一趟分配—收集
- 重复分配—收集,直到最高位分配—收集完成,则序列有序
实例分析
算法分析
- 将序列中的数据元素按个位进行分配,并将该数据元素存入相应队列
- 重复以上操作,直到序列所有数据元素均按个位存入相应队列
- 按照队列先后顺序,将每个队列中的元素连在一起构成新队列。
- 将新队列仿照以上操作进行分配(这次按百位分配)、收集
- 重复以上操作,直到序列中数据元素的最高位分配收集完成
使用场景
- 适用于关键字长度不长的整数或字符串排序
核心算法实现(c语言)
- 分配
/*
* Function: distributeRadix
* Description: 对序列进行分配
* Parameter: Queue* que 指向链队的指针
* Return: void
*/
void distributeRadix(Queue* que)
{
//初始化十个带头结点的队列
for (int i = 0; i < 10; i++)
{
initQueue(&queue[i]);
}
Node* p = (*que).front->next;
while (p != NULL)
{
int k = getKey(p);
queue[k].rear->next = p;
queue[k].rear = p;
p = p->next;
queue[k].rear->next = NULL;
}
//清空队列
clear(que);
}
- 收集
/*
* Function: collectRadix
* Description: 对分配好的队列进行收集
* Parameter: Queue* que 指向链队的指针
* Return: void
*/
void collectRadix(Queue* que)
{
int index = 0; //标记第一个非空队列位置,默认 0
for (index = 0; index < 10; index++)
{
if (&queue[index].front->next->data != NULL)
{
break;
}
}
//将第一个非空队列加入链队中
Node* p = queue[index].front->next;
while (p != NULL)
{
(*que).rear->next = p;
(*que).rear = p;
p = p->next;
(*que).rear->next = NULL;
}
//继续寻找剩下的非空队列并添加到que链队中
for (index++; index < 10; index++)
{
Node* q = queue[index].front->next;
while (q != NULL)
{
(*que).rear->next = q;
(*que).rear = q;
q = q->next;
(*que).rear->next = NULL;
}
}
//清空10个队列
for (int i = 0; i < 10; i++)
{
clear(&queue[i]);
}
//除数 用于获取数据元素某位的关键字
divisior *= 10;
}
算法测试(c语言)
#include <stdio.h>
//结点
typedef struct Node
{
int data;
struct Node* next;
}Node;
//队列
typedef struct Queue
{
Node* front;
Node* rear;
}Queue;
//队列数组,存放10个队列
Queue queue[10];
//除数 用于获取数据元素某位的关键字
int divisior = 1;
/*
* Function: initQueue
* Description: 将队列初始化为带头结点的链队
* Parameter: Queue* que 指向链队的指针
* Return: void
*/
void initQueue(Queue* que)
{
Node* p = malloc(sizeof(Node));
if (p != NULL)
{
p->data = NULL;
p->next = NULL;
(*que).front = p;
(*que).rear = p;
}
else
{
printf("node apply error!\n");
}
}
/*
* Function: push
* Description: 将数据元素从队尾入队
* Parameter:
Queue* que 指向链队的指针
int e 数据元素
* return: void
*/
void push(Queue* que, int e)
{
Node* p = malloc(sizeof(Node));
if (p != NULL)
{
p->data = e;
p->next = NULL;
(*que).rear->next = p;
(*que).rear = p;
}
else
{
printf("node apply error!\n");
}
}
/*
* Function: clear
* Description: 把队列清空
* Parameter: Queue* que 指向队列的指针
* Return: void
*/
void clear(Queue* que)
{
(*que).front->next = NULL;
(*que).rear = (*que).front;
}
/*
* Function: maxBit
* Description: 返回数据元素最大位数
* Parameter: Queue* que 指向无序序列的指针
* Return: b 最大位数
*/
int maxBit(Queue* que)
{
Node* p = (*que).front->next;
int maxData = p->data;
while(p != NULL)
{
if (maxData < p->data)
{
maxData = p->data;
}
p = p->next;
}
int b = 0;
while (maxData > 0)
{
maxData /= 10;
b++;
}
return b;
}
/*
* Function: getKey
* Description: 获取数据元素某位上的关键字
* Parameter: Node* q 指向结点的指针
* Return: k 关键字
*/
int getKey(Node* q)
{
int k = 0;
k = ((*q).data / divisior) % 10;
return k;
}
/*
* Function: distributeRadix
* Description: 对序列进行分配
* Parameter: Queue* que 指向链队的指针
* Return: void
*/
void distributeRadix(Queue* que)
{
//初始化十个带头结点的队列
for (int i = 0; i < 10; i++)
{
initQueue(&queue[i]);
}
Node* p = (*que).front->next;
while (p != NULL)
{
int k = getKey(p);
queue[k].rear->next = p;
queue[k].rear = p;
p = p->next;
queue[k].rear->next = NULL;
}
clear(que);
}
/*
* Function: collectRadix
* Description: 对分配好的队列进行收集
* Parameter: Queue* que 指向链队的指针
* Return: void
*/
void collectRadix(Queue* que)
{
int index = 0; //标记第一个非空队列位置,默认 0
for (index = 0; index < 10; index++)
{
if (&queue[index].front->next->data != NULL)
{
break;
}
}
//将第一个非空队列加入链队中
Node* p = queue[index].front->next;
while (p != NULL)
{
(*que).rear->next = p;
(*que).rear = p;
p = p->next;
(*que).rear->next = NULL;
}
//继续寻找剩下的非空队列并添加到que链队中
for (index++; index < 10; index++)
{
Node* q = queue[index].front->next;
while (q != NULL)
{
(*que).rear->next = q;
(*que).rear = q;
q = q->next;
(*que).rear->next = NULL;
}
}
for (int i = 0; i < 10; i++)
{
clear(&queue[i]);
}
divisior *= 10;
}
/*
* Function: radix
* Description: 基数排序
* Parameter: Queue* que 指向链队的指针
* Return: void
*/
void radix(Queue* que)
{
int b = maxBit(que);
for (int i = 0; i < b; i++)
{
distributeRadix(que);
collectRadix(que);
}
}
/*
* Function: print
* Description: 打印序列
* Parameter: Queue* que 指向链表的指针
* Return: void
*/
void print(Queue* que)
{
Node* p = (*que).front->next;
while (p != NULL)
{
printf("%d\t", p->data);
p = p->next;
}
printf("\n");
}
int main()
{
Queue que;
initQueue(&que);
int arr[] = {39, 135, 521, 204, 367, 45, 259, 723, 412, 68};
int len = sizeof(arr) / sizeof(int);
for (int i = 0; i < len; i++)
{
push(&que, arr[i]);
}
printf("排序前序列:\n");
print(&que);
radix(&que);
printf("排序后序列:\n");
print(&que);
return 0;
}
输出如下
参考资料
- 《数据结构与算法》北京大学出版社 2018年版 林劼 刘震 陈端兵 戴波 著
- 排序算法之链式基数排序(详解)内附大佬连接
- 1.10 基数排序