桶排序

桶排序是计数排序的变种,

对待排序列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 <iostream>
#include <vector>
#include<malloc.h>
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 <max+1 ; i++) TmpArray[i] = 0;//初始化桶,是桶中的每个元素为0;
    for (int j = 0; j <Count_intArray; j++)  //将TmpArray下标中等于intArray[i]的元素+1
        TmpArray[intArray[j]] += 1;

    int InsertIndex = 0;//指向intArray的指标
    for (int j=0; j < max + 1; j++)
    {
        for (int k = 1; k <= TmpArray[j]; k++)//需要插入的元素的个数必须>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<<intArray[i]<<' ';
    cout<<endl;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值