【数据结构】分配排序

基于分配和收集

基本思想

先将数据分配到不同的桶中
再将桶中的数据收集到一起

两种方法

桶式排序(单关键字排序)
链式基数排序(多关键字排序)

特点

排序过程无须比较关键字,而是通过“分配”和“收集”过程来实现排序
它们的时间复杂度可达到线性阶: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)

稳定性

稳定

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值