http://blog.csdn.net/houapple/article/details/6480100
http://blog.csdn.net/silangquan/article/details/8121727
桶排序 (Bucket sort)或所谓的箱排序,是一个排序算法,工作的原理是将阵列分到有限数量的桶子里。每个桶子再个别排序(有可能再使用别的排序算法或是以递回方式继续使用桶排序进行排序)。桶排序是鸽巢排序的一种归纳结果。当要被排序的阵列内的数值是均匀分配的时候,桶排序使用线性时间(Θ(n))。但桶排序并不是 比较排序,他不受到 O(n log n) 下限的影响。
例如要对大小为[1..1000]范围内的n个整数A[1..n]排序,可以把桶设为大小为10的范围,具体而言,设集合B[1]存储[1..10]的整数,集合B[2]存储(10..20]的整数,……集合B[i]存储((i-1)*10, i*10]的整数,i = 1,2,..100。总共有100个桶。然后对A[1..n]从头到尾扫描一遍,把每个A[i]放入对应的桶B[j]中。 然后再对这100个桶中每个桶里的数字排序,这时可用冒泡,选择,乃至快排,一般来说任何排序法都可以。最后依次输出每个桶里面的数字,且每个桶中的数字从小到大输出,这样就得到所有数字排好序的一个序列了。
假设有n个数字,有m个桶,如果数字是平均分布的,则每个桶里面平均有n/m个数字。如果对每个桶中的数字采用快速排序,那么整个算法的复杂度是O(n+m*n/m*log(n/m))=O(n+nlogn-nlogm)
从上式看出,当m接近n的时候,桶排序复杂度接近O(n)
当然,以上复杂度的计算是基于输入的n个数字是平均分布这个假设的。这个假设是很强的,实际应用中效果并没有这么好。如果所有的数字都落在同一个桶中,那就退化成一般的排序了。
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- extern void quick_sort(int a[], int p, int q);/* not necessary */
- struct barrel {
- int node[10];
- int count;/* the num of node */
- };
- void bucket_sort(int data[], int size)
- {
- int max, min, num, pos;
- int i, j, k;
- struct barrel *pBarrel;
- max = min = data[0];
- for (i = 1; i < size; i++) {
- if (data[i] > max) {
- max = data[i];
- } else if (data[i] < min) {
- min = data[i];
- }
- }
- num = (max - min + 1) / 10 + 1;
- pBarrel = (struct barrel*)malloc(sizeof(struct barrel) * num);
- memset(pBarrel, 0, sizeof(struct barrel) * num);
- /* put data[i] into barrel which it belong to */
- for (i = 0; i < size; i++) {
- k = (data[i] - min + 1) / 10;/* calculate the index of data[i] in barrel */
- (pBarrel + k)->node[(pBarrel + k)->count] = data[i];
- (pBarrel + k)->count++;
- }
- pos = 0;
- for (i = 0; i < num; i++) {
- quick_sort((pBarrel+i)->node, 0, (pBarrel+i)->count);/* sort node in every barrel */
- for (j = 0; j < (pBarrel+i)->count; j++) {
- data[pos++] = (pBarrel+i)->node[j];
- }
- }
- free(pBarrel);
- }
- main()
- {
- int data[] = {78, 17, 39, 26, 72, 94, 21, 12, 23, 91}, i;
- int size = sizeof(data) / sizeof(int);
- bucket_sort(data, size);
- for (i = 0; i < size; i++)
- printf("%d ", data[i]);
- }
注意这里的快速排序用的笔记中的版本。
二、桶排序
基本思想
假定输入是由一个随机过程产生的[0, 1)区间上均匀分布的实数。把区间[0,1)划分成n个相同大小的子区间,或称桶,然后将n个输入数分布到各个桶中去。因为输入数均匀分布在[0,1)上,所以一般不会有很多数落在一个桶中的情况。为得到结果,先对各个桶中的数进行排序,然后按次序把各桶中的元素列出来即可。
c语言实现
- /*BucketSort*/
- void bucketSort(elementType * r,int len)
- {
- elementType *buckets[10];//指针数组
- int n=1;//用于取整数各位上的值
- int index;//数组下标计数索引
- int indexs[10];//各个桶下标计数索引
- int i,j;
- //分配动态内存作为桶
- for(i=0;i<10;++i)
- buckets[i]=(elementType *)malloc(sizeof(elementType)*len);
- //计数索引清零
- index=0;
- for(i=0;i<10;++i)
- indexs[i]=0;
- //数组至桶
- for(i=0;i<len;++i)
- {
- n=(int)(r[i]*10);
- //printf("%d ",n);
- buckets[n][indexs[n]++]=r[i];
- }
- //sort every bucket
- for(i=0;i<10;++i)
- {
- quickSort(buckets[i],indexs[i]);
- }
- //桶至数组
- for(i=0;i<10;++i)
- for(j=0;j<indexs[i];++j)
- r[index++]=buckets[i][j];
- //释放动态内存
- for(i=0;i<10;++i)
- free(buckets[i]);
- }
这里利用快速排序为每个桶进行排序,运行结果:
算法分析
桶排序的平均时间复杂度为线性的O(N+C),其中C=N*(logN-logM)。如果相对于同样的N,桶数量M越大,其效率越高,最好的时间复杂度达到O(N)。当然桶排序的空间复杂度为O(N+M),如果输入数据非常庞大,而桶的数量也非常多,则空间代价无疑是昂贵的。此外,桶排序是稳定的。
/*****************桶排序*****************************/
struct Node
{
int key_;
struct Node *next_;
Node(int key)
{
key_ = key;
next_ = NULL;
}
};
#define bucket_size 10 //与数组元素个数相等
void buck_sort(int arr[], int num)
{
Node *bucket_table[bucket_size];
memset(bucket_table, 0, sizeof(bucket_table));
//建立每一个头节点,头节点的key保存当前桶的数据量
for (int i = 0; i < bucket_size; i++)
bucket_table[i] = new Node(0);
int maxValue = arr[0];
for (int i = 1; i < num; i++)
{
if (arr[i] > maxValue)
maxValue = arr[i];
}
for (int j = 0; j < num; j++)
{
Node *ptr = new Node(arr[j]);//其余节点的key保存数据
//映射函数计算桶号
// index = (value * number_of_elements) / (maxvalue + 1)
int index = (arr[j] * bucket_size) / (maxValue + 1);
Node *head = bucket_table[index];
//该桶还没有数据
if (head->key_ == 0)
{
bucket_table[index]->next_ = ptr;
(bucket_table[index]->key_)++;
}
else
{
//找到合适的位置插入
while (head->next_ != NULL && head->next_->key_ <= ptr->key_)
head = head->next_;
ptr->next_ = head->next_;
head->next_ = ptr;
(bucket_table[index]->key_)++;
}
}
//将桶中的数据拷贝回原数组
int m, n;
for (m = 0, n = 0; n < num && m < bucket_size; m++, n++)
{
Node *ptr = bucket_table[m]->next_;
while (ptr != NULL)
{
arr[n] = ptr->key_;
ptr = ptr->next_;
n++;
}
n--;
}
//释放分配的动态空间
for (m = 0; m < bucket_size; m++)
{
Node *ptr = bucket_table[m];
Node *tmp = NULL;
while (ptr != NULL)
{
tmp = ptr->next_;
delete ptr;
ptr = tmp;
}
}
}
/****************************************************/