《算法导论》——桶排序
- 桶排序的思想就是把区间[0, 1)划分成n个相同大小的子区间,每一个区间称为桶(bucket)。然后,将n个输入数据分布到各个桶中去。因为输入数均匀且独立均匀分布在[0, 1)上,所以一般不会有很多数落在一个桶中的情况。为得到结果,先对各个桶中的数进行排序,然后按次序把各个桶中的元素列出来即可。时间复杂度O(n).
- 在桶排序算法中,假设输入的是一个含n个元素的数组A,且每个元素满足0≤A[i]<1。另外,还需要一个辅助数组B[0…n-1]来存放链表(桶),并假设可以用某种机制来维护这些表
伪代码
c++代码
#include "iostream"
#include "stdlib.h"
using namespace std;
struct Node
{
double value;
struct Node *next;
};
void BUCKET_SORT(double* array, int len)
{
int count = 0;
Node *bucket = new Node [len] ; //开辟了一块连续的存储len个Node(头节点)的数组
for (int i = 0; i < len; i++) //初始化头
{
bucket[i].value = 0;
bucket[i].next = NULL;
}
for (int j = 0; j < len; j++)
{
Node *insert = new Node;
insert->value = array[j];
insert->next = NULL;
int temp = array[j] * 10;
if (bucket[temp].next == NULL) //链表中只有头节点
{
bucket[temp].next = insert; //直接插入后
}
else //有多个节点,排序插入
{
Node *q = &bucket[temp]; //头节点
Node *p = bucket[temp].next;
while (p!= NULL &&( p->value <= array[j]))
{
p = p->next;
q = q->next;
}
q->next = insert;
insert->next = p;
}
}
for (int k = 0; k < len; k++)
{
Node *p = bucket[k].next;
while (p != NULL)
{
array[count++] = p->value;
p = p->next;
}
}
}
void main()
{
double a[] = { 0.12, 0.13, 0.45, 0.53, 0.65, 0.48, 0.34, 0.45 };
int length = sizeof(a) / sizeof(a[0]);
BUCKET_SORT(a, length);
for (int i = 0; i < length; i++)
{
cout << a[i] << " ";
}
cout << endl;
system("pause");
}
桶排序也可以拓展至整数部分。
转载
3. 桶排序在海量数据中的应用
一年的全国高考考生人数为500 万,分数使用标准分,最低100 ,最高900 ,没有小数,你把这500 万元素的数组排个序。
分析:对500W数据排序,如果基于比较的先进排序,平均比较次数为O(5000000*log5000000)≈1.112亿。但是我们发现,这些数据都有特殊的条件: 100=<score<=900。那么我们就可以考虑桶排序这样一个“投机取巧”的办法、让其在毫秒级别就完成500万排序。
方法:创建801(900-100)个桶。将每个考生的分数丢进f(score)=score-100的桶中。这个过程从头到尾遍历一遍数据只需要500W次。然后根据桶号大小依次将桶中数值输出,即可以得到一个有序的序列。而且可以很容易的得到100分有**人,501分有*人。
实际上,桶排序对数据的条件有特殊要求,如果上面的分数不是从100-900,而是从0-2亿,那么分配2亿个桶显然是不可能的。所以桶排序有其局限性,适合元素值集合并不大的情况。