一 、介绍:什么是桶排序?
桶排序是在已经数据的范围的条件下,创建若干个桶,根据相应的比较规则将待排数据落入各个对应的桶中,最后扫描桶来实现排序。
其思想是:若干元素分布在某个区间[a,b],则将该区间划分为n个大小相同的子区间,使每一个元素都均匀且独立的分布在某个子区间上。我们把这n个子区间称为桶,再对每个桶进行桶内排序,最后依次合并每一个桶。
二 、基本步骤
将原数组所属区间均分为若干子区间,即建立若干个桶;
遍历原数组,并将数据放入到各自对应的桶中;
对每一个非空的桶进行排序;
依次合并每一个桶,即将其按顺序放入原数组中,最后即可得到一个排好序的新数组。
三 、应用示例
1 、将20个0~100范围内的整数排序。
排序流程大致如图(PS:图片摘自网络,原图地址:http://www.myexception.cn/program/1668221.html)
我的代码如下:
#include<bits/stdc++.h>
using namespace std;
vector<int>bucket[10];//由于数据范围为0~100,不妨根据其十位数大小划分10个桶 (100即放在“10”这个桶)
int a[50];
int n,t=0;
int index(int v)//确定每个元素所在的“桶 ”
{
return v/10;
}
void bucket_sort(int a[])
{
for(int i=1;i<=n;i++)
{
int m=index(a[i]);
bucket[m].push_back(a[i]);//将原数组中每个元素放入对应的桶
}
for(int i=0;i<=10;i++)
{
sort(bucket[i].begin(),bucket[i].end());//桶内排序,也可以使用其他排序方法(比如插入排序)
int len=bucket[i].size()-1;
for(int j=0;j<=len;j++)//合并桶,将每一个桶内的元素放回原桶
{
t++;
a[t]=bucket[i][j];
}
}
}
int main()
{
scanf("%d",&n);//输入排序数据个数
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
bucket_sort(a); //排序
for(int i=1;i<=n;i++)
printf("%d ",a[i]);//打印结果
return 0;
}
可以输入一下数据进行验证:
20
8 4 2 69 47 32 85 66 98 85 74 15 87 45 25 78 62 34 0 100
四 、基于计数排序的简化版本
基本思路与原来大致一致,只不过划分桶时,每一个单位就划分一个桶,将每一个元素装入对应的桶。(就是在0~最大值范围内,每个数都有一个桶)注意!此时桶里装的并非元素本身,而是该元素的出现次数。最后合并桶即可。
例:对十个数据进行排序
我的代码如下:
#include<bits/stdc++.h>
using namespace std;
int bucket[500];
int a[50];
int n,maxn=0;
void bucket_sort(int a[])
{
int t=0;
for(int i=0;i<=maxn;i++)
bucket[i]=0;//清空桶
for(int i=1;i<=n;i++)
bucket[a[i]]++; //统计每个元素的出现次数
for(int i=0;i<=maxn;i++)//合并桶,将其放回原数组中
for(int j=1;j<=bucket[i];j++)
{
t++;
a[t]=i;
}
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
if(maxn<a[i])//找出最大值
maxn=a[i];
}
bucket_sort(a);//排序
for(int i=1;i<=n;i++)
printf("%d ",a[i]);//打印结果
return 0;
}
可输入如下数据进行验证:
10
4 5 2 4 3 9 7 23 5 8
五 、桶排序优缺点分析
1 、优点:
桶排序的时间复杂度为O(n+c)(c为桶内排序所使用的排序方式的复杂度),而当桶越多,其时间效率就越高,利用桶排序,可以实现线性的时间复杂度!
此外,桶排序是稳定的。
2 、缺点
桶排序的缺点很明显,就是太耗空间了。桶越多,空间复杂度就越高(这也算是以空间换时间了吧……然而在NOIP范围内,空间什么的就是随便浪费的!)
3 、使用范围
1.处理数据非负(当然也不是不可以处理负数,但比较麻烦)
2.数据较为集中,不能太分散