您的位置:首页 > 其它

排序算法——基数排序

2016-12-23 17:04 183 查看
       基数排序不需要进行关键字的比较,而是通过“分配”和“收集”过程来实现排序的,是一种借助多关键字排序的思想对单关键字排序的方法。它通过比较关键字不同位上的字符的大小进行排序,每一趟排序过程并不产生有序区,也就是说在最后一趟排序结束前,所有元素并不一定都归位了。基数排序分为最低位优先(LSD)和最高位优先(MSD)。本博文只介绍最低位优先(LSD),不过,只要理解了最低位优先(LSD),那么最高位优先(MSD)也就很容易理解。

       基数排序并不是使用数组保存待排序元素,而是使用一个单链表保存,并且每个元素的关键字并不是一个数字,而是用一个字符数组表示数字。如,使用长度为10的字符数组,对于数字24,则字符数组的第0位取值为4,第1位取值为2,第2位到第9位取值为0。

/**
* 基数排序
*
* 算法:基数排序(Radix Sort)
* 输入:待排序元素的单链表指针,基数,关键字位数
* 输出:
* 原理:元素R[i]的关键字R[i].key由d位数字组成,即R[i].key=k[d-1]k[d-2]…k[0],每一个数字表示关键字的一位,其中k[d-1]是最高位,k[0]是最低位,每一位的值都在[0,r)之间。例,对于一个十进制数,如249,它是一个3位数,所以d=3,最高位k[2]=2,最低位k[0]=9,基数r=10,因为每一位数都在[0,9]之间。
最低位优先:先按最低位的值对元素进行排序,对得到得到的序列,再按次低位进行排序,……,由低位向高位,每一次排序都是根据关键字的一位对元素进行排序,直至最高位。
* 过程:
*  1)按照最低位对元素进行排序,在排序过程中将它们暂时保存在多个链表中(该过程称为分配)
*  2)将暂时保存在链表中的元素,重新保存到一个单链表中,此时所有元素按照最低位是从小到大排序的(该过程称为收集)
*  3) 按照次低位对元素进行排序,重复上述操作
*  4)...
*  5) 按照最高位对元素进行排序,重复上述操作
*  6)最终得到的单链表p中的元素递增排序
*
* 时间复杂度为O(d*(n+r)),空间复杂度为O(r),稳定的排序方法。其中,n为元素个数,r为基数
*/

#define NULL 0
#define MAXD 10

typedef struct node
{
char data[MAXD]; //MAXD为最大的关键字位数,把关键字表示为字符数组
struct node *next;
}RecPoiType;

#define MAXR 10

void radixSort(RecPoiType *&p, int r, int d)
{
//定义各链表的首尾指针
RecPoiType *head[MAXR], *tail[MAXR], *t;
int i, j, k;
//从低位到高位循环
for (i = 0; i <= d - 1; i++)
{
//初始化各链队首、尾指针
for (j = 0; j < r; j++)
head[j] = tail[j] = NULL;
//分配:对于原链表中每个节点循环
while (p != NULL)
{
//找第k个链队
k = p->data[i] - '0';
if (head[k] == NULL) //第k个链队空时,队头队尾均指向*p
{
head[k] = p;
tail[k] = p;
}
else //第k个链队非空时,*p入队
{
tail[k]->next = p;
tail[k] = p;
}
//取下一个待排序的元素
p = p->next;
}
//重新用p来收集所有节点
p = NULL;
//若第j个链队是第一个非空链队
for (j = 0; j < r; j++)
{
if (head[j] != NULL)
{
if (p == NULL)
{
p = head[j];
t = tail[j];
}
else //若第j个链队是其它非空链队
{
t->next = head[j];
t = tail[j];
}
}
}
//最后一个节点的next域置NULL
t->next = NULL;
}
}

       为了让大家更好的理解基数排序,接下来会给出一个例子,通过例子可以很容易理解基数排序的原理。本例子摘自于教科书中。

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息