桶排序是计数排序的变种,
对待排序列A,若其中最大元素为k,则需要k+1个桶(数组C[0~k]),初始时,对每个桶赋值为0。对于元素A[i]=x,则相应的桶x中元素个数加1,即C[[A[i]]++=C[x]++。也就是,对元素x,桶x记录元素x的个数。然后遍历桶数组,把桶数组中元素大于0的下标作为值按次序依次填入待排序数组,元素的值作为重复填入该下标的次数,遍历完成则排序结束序列有序。
二,桶排序的示例
①将10万个人的年龄进行桶排序
假设有10万个人的年龄数据,年龄范围默认是0-99,如何对这10万个数据进行排序?
如果用快排啊、归并排序啊...这样的排序算法是可以。但是这样的排序问题更适合桶排序。采用桶排序的方法如下:
建立100个桶,这可以用一个 一维数组来表示。a[0...99],依次扫描10万条数据,根据每条数据的值,记录到桶中。比如,第10个人的年龄是18岁,则a[18]++ (这是将出现的频率记录在桶中,是计数,它是将待排序的元素本身进行比较,而不是将“待排序的元素的组成部分”进行比较)
然后,扫描这100个桶,即可得到有序的数组。
如:一个简单的示例: 所有的数据都在0-5范围内:
4,5,2,3,1,4,3,2,1,5,2,2,4,5,1,3,4,1,3,2,2
排序后.....
1,1,1,1,2,2,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5
②将20个范围为0-999的整数进行排序
如果按照①中的思路,则需要创建999个桶,然后进行一趟桶排序即可。
但是还有另外一种方式,只创建10个桶,但是要进行3趟桶排序。
10个桶对应0-9 一共10个不同的数字,说白了就是一个长度为10的整型数组。3趟桶排序是因为:0-999范围内的数由3个位组成:个位、十位、百位
第一趟对个位数进行桶排序,根据个位数的值,将该数放入对应的桶中,比如425,个位数为5,则将425放到a[5]中---(这是将元素本身放到桶中,不是计数,这种方式待排序的元素个数不能超过桶的个数!!!)
第二趟对十位数进行桶排序,根据十位数.....
第三趟对百位数进行桶排序,根据百位数.....
具体的实现可以这样:
在第一趟桶排序时,将待排的20个数依次放到桶中。然后,再把这20个数拷贝回原数组,然后再根据 十位 数排序:根据十位数的大小 将这20个数 按顺序放到桶中,然后再把十位数有序的桶中的数据复制回原数组......百位数....
最终,原数组中的数据就是 已经排好序的数据了。
(注意:可能一个桶里面存储了多个 数,比如: 425, 685 在第一趟桶排序时会被放入到同一个桶中)
③将100个长度固定(比如5)的字符串进行排序
有100个字符串,每个字符串的长度为5,字符串只由小写字母表中的字母组成。
小写字母表共有26个,故需要26个桶。每个字符串的长度为5,需要进行5趟桶排序。
第一趟桶排序对所有字符串中最后一个字符进行比较,并将该字符串放到相应的桶中(是将元素本身放到桶中)
然后,再把桶中的数据拷贝回原数组,以便进行第二趟比较。(因为,在下一趟桶排序中又需要将字符串根据下一个比较字符复制到桶中)
第二趟桶排序对所有字符串中的倒数第二个字符比较,并将该字符串放到相应的桶中
....
....
可以看出,这种类型的桶排序,并不是比较元素本身并记录出现的次数,而是比较元素的组成部分并将元素本身放到桶中。因此,需要根据实际问题,采用何种记录方式。
比如,字符串 "china" ,所谓比较元素的组成部分是指,依次比较 "china" 中的各个字符 'a' 'n' 'i' 'h' 'c'。然后将字符串 "china" 存储到桶中。
四,桶排序复杂度分析
桶排序可以做到线性时间复杂度,比如上面的10万个人的年龄排序。将10万条年龄数据输入,复杂度是O(N),输出排序结果时遍历每个桶复杂度是O(M),故总时间复杂度是O(M+N),桶0~M,N为元素个数。而这种情况下桶的个数远远小于数据条数。
对于使用多趟桶排序的情形,时间复杂度是O(p(N+b)),其中N是输入的数据量,b是桶的个数,p是桶排序的趟数。比如上面提到的字符串排序,p是字符串的长度,N是字符串个数,b则是桶的数目(也即字符串中字符的种类(a-z),26种)
代码:#include
#include
#include
using namespace std;
void BucketSort(int intArray[], int Count_intArray, int max)
{
//待排序序列intArray的元素都是非负整数
//设待排序序列intArray的元素有Count_intArray个
//其取值范围为0到max,则我们新建一个大小为max+1的临时数组并把初始值都设为0
//此处是开辟max+1而不是max,因为比如给909,...0排序,是有1000个数,需要开辟999+1长度的数组
int TmpArray[max+1];//开辟一个新数组,这个数组即为桶;
for (int i=0; i 1
intArray[InsertIndex++] = j;
}
free(TmpArray);
}
int main()
{
int intArray[10] = { 999,55,10,1,0,1,87,45,55,4 };
int Count_intArray = 10;
int max = 999;
BucketSort(intArray, Count_intArray, max);
for (int i = 0; i < 10; i++)
cout<