基于分配和收集
基本思想
先将数据分配到不同的桶中
再将桶中的数据收集到一起
两种方法
桶式排序(单关键字排序)
链式基数排序(多关键字排序)
特点
排序过程无须比较关键字,而是通过“分配”和“收集”过程来实现排序
它们的时间复杂度可达到线性阶:O(n)。
桶式排序
假设待排序的记录的值在0~m-1之间
设置m个桶,
依次扫描待排序的记录,R[1],…,R[n-1],把关键字等于k的记录全都装入到第k个箱子里(分配),
然后按序号依次将各非空的箱子首尾连接起来(收集)。
顺序存储
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int main()
{
int b[100],n,i,j,m=0,x;
memset(b,0,sizeof(b));//初始化
cin>>n;
for(i=1;i<=n;i++)
{
cin>>x;
b[x]++;//将等于写的值全部装入第x桶中
}
for(i=0;i<=1000;i++)//输出排序结果
if(b[i]>0)
cout<<i<<" "<<b[i]<<endl;//数值及其出现的次数
cout<<endl;
return 0;
}
链式存储
struct Node{
int key;
Node * next;
}
struct head
{
Node *first, *rear;
};
void distribute(Node *first, int n, head *list){
Node *p,*q;
p=first; int data;
while(p) {
data=p->data; //桶的编号
q=p->next;
if(list[data].first)
list[data].rear->next=p;
else
list[data].first=p;
list[data].rear=p;
list[data].rear->next=NULL;
p=q;
}
}
void collect( head *list, Node *&first,int m){
int i=0,j;
while(list[i].first==NULL) i++; //寻找第一个非空的桶
if(i>m) return;
first=list[i].first;
while(i<=m) {
j=i+1;
while(list[j].first==NULL) j++;
if(j>m) return;
list[i].rear->next=list[j].first;
i=j;
}
}
int main(){
Node *s,*first; head *list;
int m;cin>>m;
list=new head[m];
for (int i=0;i<=m;i++){
list[i].first=NULL; list[i].rear=NULL;}
int n;
cin>>n;
first=NULL;
for( i=0;i<n;i++)
{ s=new Node; cin>>s->data; s->next=first; first=s; }
distribute(first,n,list);
collect(list,first,m);
Node *p=first;
while(p){
cout<<p->data<<"\t"; p=p->next; }
cout<<endl;
return 0;
}
特点:
需要较多的桶
时间复杂性
一次分配,O(n)
一次收集,O(m)
O(n+m)
空间复杂性
O(m)
稳定性
稳定
基数排序
基本思想
从关键字的最“低位”开始,将关键字分配到r(基数)个堆(桶)中;
按桶的编号将关键字收集起来;
然后,以“次低位”将关键字又分配到r个桶中;再收集,……,重复直到“最高位”为止,这时,以按关键字有序。
void distribute(Node *first, int n, head *list,int d){
Node *p,*q; p=first; int data, s,t;
while(p) {
data=p->data;
s=pow(10,d);t=s/10;data=data%s;data=data/t;
q=p->next;
if( list[data].first)
{list[data].rear->next=p; list[data].rear=p;}
else
list[data].first=list[data].rear=p;
list[data].rear->next=NULL;
p=q;
}
void collect( head *list, Node *&first,int m){
int i=0,j;
while(list[i].first==NULL) i++;
if(i>m) return;
first=list[i].first;
while(i<=m) {
j=i+1;
while(list[j].first==NULL) j++;
if(j>m) return;
list[i].rear->next=list[j].first;
i=j;
}
}
main函数
......
int d;
cout<<"Please input the size of a data:";
cin>>d;
for(i=1;i<=d;i++) //处理每一“位”(个位、十位...)
{
distribute(first,n,list ,i);
collect(list,first,m);
for (int i=0;i<=m;i++)
{
list[i].first=NULL;
list[i].rear=NULL;
}
}
时间复杂性
多次分配,多次收集
一次分配的时间复杂性O(n)
一次收集的时间复杂性O(radix)
分配与收集的次数:数的位数(d)
O(d(n+radix))
空间复杂性
O(radix)
稳定性
稳定