桶排序
桶排序(Bucket Sort)是对基数排序的一个变种。在排序过程中没有用到计数数组,而是用不同的桶来暂时存储关键字。看一个示意图:
排序序列 123 234 45 111 6 128
整个过程就是在不断地分配、收集。并且每一个桶都是队列,所以收集的时候得按先进先出的原则,且从第0个桶开始收集。
在实际应用中,根据桶的创建策略,桶排序也有不同的写法。下面给出两种不同的桶创建方式。一、使用静态队列创建桶。二、使用二维数组模拟桶。
静态队列桶
#include<iostream>
#include<iomanip>
using namespace std;
//记录类型
typedef struct record
{
int key;
int next;
}Record;
//静态队列
typedef struct queue
{
//队头
int head;
//队尾
int tail;
}StaticQueue;
//获取最大位数
int get_max_digit(int array[], int n)
{
int digit, max;
digit = 0;
max = array[0];
for (int i = 1; i < n; i++)
{
if (array[i] > max)
max = array[i];
}
while (max)
{
digit++;
max /= 10;
}
return digit;
}
/*
收集
把10个桶连接起来
*/
void collect(Record rec[], StaticQueue queue[], int& first)
{
//k是桶号
int tail, k = 0;
//先找到第一个非空的桶
while (queue[k].head == -1)
k++;
//用first记录第一个记录的位置,为下次分配使用
first = queue[k].head;
tail = queue[k].tail;
while (k < 9)
{
k++;
while (k < 9 && queue[k].head == -1)
k++;
//把上一个桶的尾部和当前桶的头部连接起来
if (queue[k].head != -1)
{
rec[tail].next = queue[k].head;
tail = queue[k].tail;
}
}
rec[tail].next = -1;
}
/*
分配
把n个记录分配到10个桶中
r:从右数按第r位排序(r=1,2...)
first:第一个记录的下标
*/
void distribute(Record rec[], int r, int first, StaticQueue queue[])
{
//先把队列初始化
int i, d, cur = first;
for (i = 0; i < 10; i++)
queue[i].head = -1;
i = d = 1;
while (i < r)
{
i++;
d *= 10;
}
int k;
//把记录分配每一个桶中
while (cur != -1)
{
k = (rec[cur].key / d) % 10;
//桶空,则当前记录是第一个
if (queue[k].head == -1)
queue[k].head = cur;
else//桶非空,则当前记录连接到尾部
rec[queue[k].tail].next = cur;
//修改队列尾部,这一句不可忘了
queue[k].tail = cur;
//继续给下一个记录分桶
cur = rec[cur].next;
}
}
/*
重排
first:第一个记录的下标
*/
void arrange(Record rec[], int n, int first)
{
int i, j = first;
Record temp;
for (i = 0; i < n - 1; i++)
{
temp = rec[j];
rec[j] = rec[i];
rec[i] = temp;
rec[i].next = j;
j = temp.next;
while (j <= i)
j = rec[j].next;
}
}
/*
基数排序
array:待排序序列
n:序列大小
*/
void RadixSort(int array[], int n)
{
//对排序序列进行封装
int i;
Record *rec = new Record[n];
for (i = 0; i < n; i++)
{
rec[i].key = array[i];
rec[i].next = i + 1;
}
rec[n - 1].next = -1;
/*
创建静态队列,每一个队列相当于一个桶
对于十进制数,只需10个桶即可
*/
StaticQueue queue[10];
//获取最大排序位数
int digit = get_max_digit(array, n);
int first = 0;
for (i = 1; i <= digit; i++)
{
distribute(rec, i, first, queue);
collect(rec, queue, first);
}
//重排
arrange(rec, n, first);
//回放
for (i = 0; i < n; i++)
array[i] = rec[i].key;
//释放空间
delete[]rec;
}
//打印
void print(int array[], int n)
{
for (int i = 0; i < n; i++)
cout << setw(6) << array[i];
cout << endl;
}
int main()
{
cout << "******桶排序(静态队列)***by David***" << endl;
int array[] = { 123, 234, 45, 111, 6, 128 };
int n = sizeof(array) / sizeof(int);
cout << "原序列" << endl;
print(array, n);
cout << "桶排序" << endl;
RadixSort(array, n);
print(array, n);
system("pause");
return 0;
}
运行
代码下载:桶排序(静态队列)
二维数组桶
#include<iostream>
#include<iomanip>
using namespace std;
//最大排序个数
const int N = 12;
//分配
void distribute(int array[], int n, int bucket[][N+1], int r)
{
int i;
//对桶进行初始化,bucket[i][0]存放的是第i个桶中元素个数
for (i = 0; i < 10; i++)
bucket[i][0] = 0;
int d;
i = d = 1;
while (i < r)
{
d *= 10;
i++;
}
int k;
for (i = 0; i < n; i++)
{
k = (array[i] / d) % 10;
bucket[k][0]++;
bucket[k][bucket[k][0]] = array[i];
}
}
//收集
void collect(int array[], int n, int bucket[][N+1])
{
int i, j, index;
index = 0;
for (i = 0; i < 10; i++)
for (j = 1; j <= bucket[i][0]; j++)
array[index++] = bucket[i][j];
}
//获取最大位数
int get_max_digit(int array[], int n)
{
int digit, max;
digit = 0;
max = array[0];
for (int i = 1; i < n; i++)
{
if (array[i] > max)
max = array[i];
}
while (max)
{
digit++;
max /= 10;
}
return digit;
}
//桶排序
void BucketSort(int array[], int n)
{
int digit = get_max_digit(array, n);
int i;
int bucket[10][N+1];
for (i = 1; i <= digit; i++)
{
//分配
distribute(array, n, bucket, i);
//收集
collect(array, n, bucket);
}
}
//打印
void print(int *a, int n)
{
for (int i = 0; i < n; i++)
cout << setw(6) << a[i];
cout << endl;
}
int main()
{
cout << "******桶排序(二维数组)***by David***" << endl;
int array[] = { 123, 234, 45, 111, 6, 128 };
int n = sizeof(array) / sizeof(int);
cout << "原序列" << endl;
print(array, n);
cout << "桶排序" << endl;
BucketSort(array, n);
print(array, n);
system("pause");
return 0;
}
运行
代码下载:桶排序(二维数组)
小结
上面的两种方式都是桶排序的具体实现,总体上是分配和收集的过程。不过细节很多,需要仔细看代码。
转载请注明出处,本文地址:http://blog.youkuaiyun.com/zhangxiangdavaid/article/details/37668921
若有所帮助,顶一个哦!
专栏目录: