基数排序
基本要求:
从键盘上输入n个程度为m的整数,要求输出这些整数的升序排列。
具体要求:
- 使用的数据结构是队列,利用顺序队列来实现
- 有良好的人机交互
- 能够输出每一趟分配和收集的情况
基本概念:
基数排序属于分配式排序、又称桶子法。通过键值的查询,将要排序的元素分配至某些“桶”中,以达到排序的作用。
具体思想:
以整形为例,将整形10进制按每位拆分,然后从低位到高位依次比较
主要分为两个过程:
分配,先从个位开始,根据位值(0-9)分别放到0~9号桶中
收集,再将放置在0~9号桶中的数据按顺序放到数组中
重复分配收集过程,从个位到最高位为重复次数
代码实现:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define Radix 10 //代表Radix(10)个队列
typedef int QElemType;
typedef struct
{
QElemType *base; //初始化的动态分配空间,存储数据
int front; //头指针,指向队列头元素,用来移动
int rear; //尾指针,指向队列尾元素的下一位置,确定长度
} SqQueue;
//distribute进行第n趟分配
//原始数据保存在Q.base数组中
//ArrType是SqQueue类型的数组,
void distribute(SqQueue &Q,int n,SqQueue ArrType[])
{
//quot-商
//rem-存储每个数据的第n位(即第1位、第2位...第n位)的值
int i,c,temp,quot,rem;
//for置空Radix(10)个队列
for(i=0; i<Radix; i++)
ArrType[i].front=0;
//for处理每个数据的第n位
for(i=0; i<Q.rear; i++)
{
//将第i个数据暂存到quot
quot=Q.base[i];
c=0;
//while计算第i个数据的第n位的值并保存到rem
while(c<n)
{
c++;
rem=quot%Radix;
quot/=Radix;
}
//将第n位为rem的数据复制到第rem个队列
//即根据数据的第n位的数字rem,将数据分配到第rem个队列的尾部
ArrType[rem].base[ArrType[rem].front++]=Q.base[i];
}
printf("第%d趟分配之后的情况是:\n",n);
for(i=0; i<Radix; i++)
{
temp=ArrType[i].front;
//if如果第i个队列不为空
if(temp>0)
{
printf("队列[%d]队头指针front->",i);
for(c=0; c<temp-1; c++)
printf("%d-",ArrType[i].base[c]);
printf("%d<-队列[%d]队尾指针rear\n",ArrType[i].base[temp-1],i);
}
}
}
//collect进行第n趟收集
//ArrType保存了第n-1趟分配的结果
void collect(SqQueue &Q,int n,SqQueue ArrType[])
{
//collected记录已收集数据的数量
int i,collected=0;
//for将数组ArrType中的数据收集到int型数组Q.base中
for(i=0; i<Radix; i++)
{
//if如果第i个队列不空,就收集它的数据
if(ArrType[i].front!=0)
{
//进行收集(简单地复制到Q.base数组就行了)
memcpy(Q.base+collected,ArrType[i].base,ArrType[i].front*sizeof(int));
collected+=ArrType[i].front;
}
}
printf("第%d趟收集之后的情况是:\n",n);
for(i=0; i<=Q.front-1; i++)
{
printf("%d ",Q.base[i]);
}
printf("\n\n");
}
//计算每个队列的初始长度(为数据量的1/Radix)
void Ord(SqQueue &Q,SqQueue ArrType[],int M)
{
int i;
int temp=M;
for(i=0; i<Radix; i++)
{
//为第i个队列分配空间
ArrType[i].base=(int*)calloc(temp,sizeof(int));
ArrType[i].rear=temp;
}
}
//for进行M(M为输入的每个数据的长度)趟分配和收集
void RadixSort(SqQueue Q,int M,SqQueue ArrType[])
{
for(int i=1; i<=M; i++)
{
distribute(Q,i,ArrType);
collect(Q,i,ArrType);
}
}
int main()
{
int i,M;
SqQueue Q,ArrType[Radix];
printf("请输入每个数据的长度:");
scanf("%d",&M);
printf("请输入共有多少个数据:");
scanf("%d",&Q.rear);
Q.base=(int*)calloc(Q.rear,sizeof(int));
Q.front=0;
printf("请输入%d个长度为%d的数据:\n",Q.rear,M);
for(i=0; i<Q.rear; i++)
scanf("%d",&Q.base[Q.front++]);
printf("\n");
Ord(Q,ArrType,M);
RadixSort(Q,M,ArrType);
//以下的free释放动态分配的内存
free(Q.base);
for(i=0; i<Radix; i++)
free(ArrType[i].base);
system("PAUSE");
return 0;
}
数据处理:
尾言:
基数排序法是属于稳定性的排序,其时间复杂度为O (nlog(r)m),其中r为所采取的基数,而m为堆数
在某些时候,基数排序法的效率高于其它的稳定性排序法。