数据结构-排序-桶排序
先看下桶排序的基本思想
假定排序的值都在0~m-1之间,设置m个桶,依次把值为i的记录分配到第i个桶中,然后把个个桶的记录依次收集起来。
首先上下结构图
下标 | key | next |
0 | 3(1) | 1 |
1 | 5(1) | 2 |
2 | 3(2) | 3 |
3 | 1 | 4 |
4 | 5(2) | 5 |
5 | 6 | 6 |
6 | 3(3) | -1 |
这就是我们用静态链表存储待的排序记录,我们会让first指向下标为0的地方,只要next不为-1就接着遍历。
初始化代码如下
struct Node
{
int key;
int next;//记录下一个键值在数组中的下标
};
//传入参数Node r[],n 这里其实是默认了node数组里面key值已经存在
for(int i=0;i<n;i++)
{
r[i].next=i+1;
}
r[n-1].next=-1;//设置最后一个的next为-1
first=0;
然后我们会传入某个值,比如这里最大的数为6,我们传个7或者8差不多偏大点的数字作为桶的个数。这里假设传m个
然后构造m个队列,为了存储以后相同的元素。
构造队列如下:
struct QueueNode//定义静态链队列存储桶
{
int front;
int rear;
};
//然后申明一组数组就行,m将是我们传入的参数
QueueNode q[m];//初始化m个静态队列
for(int i=0;i<m;i++)
q[i].front=q[i].rear=-1;
我们现在要把序列传入,然后分配
先放图 1图是待排序 2图是排序队列
下标 | key | next |
0 | 3 | 1 |
1 | 2 | 2 |
2 | 3 | -1 |
下标 | front | rear |
0 | -1 | -1 |
1 | -1 | -1 |
2 | 1 | 1 |
3 | 0 | 2 |
4 | -1 | -1 |
遍历下标0的时候发现key=3,我们就去排序队列下标3的地方把front和rear都设为0,就相当于吧下标入队
然后遍历到下标2时候,发现key又=3我们就找到排序组的rear,这个rear的作用可以看作保存了上一次的入队的值在待排序组的下标
然后我门找到待排序组中这个数,怎么获取就是通过 ----- 待排序组【排序组【当前key值】.rear】里面的排序组【当前key值】.rear就是获取上次入队的下标。
然后我们只需要------待排序组【排序组【当前key值】.rear】=当前遍历下标就行了
排序后我们观察待排序图就是这样
下标 | key | next |
0 | 3 | 2 |
1 | 2 | -1 |
2 | 3 | -1 |
注意这里的下标0的next就变成了2,下标2中正好是3
代码如下
//分配算法
void Distribute(Node r[],int n,QueueNode q[],m,int first)
{
int i=first;//first为静态链表的头指针,从下标0开始存放待排序序列。
while(r[i].next!=-1)//遍历待排序组
{
int k=r[i].key; //获取key值
if(q[k].front==-1)q[k].front=i;//处理队列为空,则把待排序的下标插入队列的front
else r[q[k].rear].next=i;//假如改队列不为空就把待排序队列上个同值的next标记为下当前的i值
q[k].rear=i; //修改队尾指针
i=r[i].next; //i后移动,处理下一个记录
}
}
接下来是收集操作就是把已经排序好的队列首位相连接
我们同样还是用上面那323的简单例子,一步步将
这是我们的原料,我们则么把队列都连起来呢?
首先我们看右边图,我们先找到不为空的序列,很简单判断front是不是-1就行了
然后遍历到2,找到front=1,发现next=-1说明没有下一个同样的值了,这时候我们已经遍历完一个队列,我们为了可以让这个队列的下一个可以接上,我们设个last保存当前下标
也就是1,然后我们接着遍历排序组,到了3,front!=-1,我们就把 ----待排序组[last].next=排序组[当前下标].front这样就首位相连了,然后再保存当前的rear的值到last继续下一个首尾相连
//收集算法
void collect(Node r[],int n,QueueNode q[],int m,int first)
{
int k=0;
while(q[k].front!=-1)//找非空队列
k++;
first=q[k].front;//获取第一个非空的排序组的front
int last=q[k].rear; //获取第一个非空的排序组的rear
while(k<m)//遍历排序组每一个队列
{
k++;
if(q[k].front!=-1) //如果队列不为空
{
r[last].next=q[k].front; //q[k].font是第一个入队的下标,也就是待排序中第一个出现这个值的下标
//r[last]是待排序中最后一个出现这个值的位置,把它的next指向第一个入队的下标
last=q[k].rear; //q[k].rear的值表示待排序组中最后一次出现k值的下标
}
}
r[last].next=-1;//待排序 最后一个设为-1
}
全部代码如下:
#include<iostream>
using namespace std;
struct Node
{
int key;
int next;//记录下一个键值在数组中的下标
};
struct QueueNode//定义静态链队列存储桶
{
int front;
int rear;
};
//分配算法
void Distribute(Node r[],int n,QueueNode q[],int m,int first)
{
int i=first;//first为静态链表的头指针,从下标0开始存放待排序序列。
while(r[i].next!=-1)//遍历待排序组
{
int k=r[i].key; //获取key值
if(q[k].front==-1)q[k].front=i;//处理队列为空,则把待排序的下标插入队列的front
else r[q[k].rear].next=i;//假如改队列不为空就把待排序队列上个同值的next标记为下当前的i值
q[k].rear=i; //修改队尾指针
i=r[i].next; //i后移动,处理下一个记录
}
}
//收集算法
void collect(Node r[],int n,QueueNode q[],int m,int first)
{
int k=0;
while(q[k].front!=-1)//找非空队列
k++;
first=q[k].front;//获取第一个非空的排序组的front
int last=q[k].rear; //获取第一个非空的排序组的rear
while(k<m)//遍历排序组每一个队列
{
k++;
if(q[k].front!=-1) //如果队列不为空
{
r[last].next=q[k].front; //q[k].font是第一个入队的下标,也就是待排序中第一个出现这个值的下标
//r[last]是待排序中最后一个出现这个值的位置,把它的next指向第一个入队的下标
last=q[k].rear; //q[k].rear的值表示待排序组中最后一次出现k值的下标
}
}
r[last].next=-1;//待排序 最后一个设为-1
}
//桶排序算法
void BucketSocket(Node r[],int n, int m)
{
for(int i=0;i<n;i++) //初始化静态链表
r[i].next=i+1;
r[n-1].next=-1;
int first=0;
QueueNode q[m];//初始化m个静态队列
for(int i=0;i<m;i++)
q[i].front=q[i].rear=-1;
Distribute(r,n,q,m,first); //分配
collect(r,n,q,m,first); //收集
}