排序算法之桶排序

原文:微信公众号:程序员小灰——什么是桶排序

1 桶排序

桶排序 (Bucket sort)或所谓的箱排序,是一个排序算法,工作的原理是将数组分到有限数量的桶子里。每个桶子再个别排序(有可能再使用别的排序算法或是以递归方式继续使用桶排序进行排序)。

2 原理

根据最大值最小值创建多个桶,确定各个桶之间的跨度,然后遍历原始数列,把各元素放到对应的桶中,先是每个桶内的元素各自排序,然后遍历输出所有的桶内的所有元素,输出结果即是排序好的数组。

桶排序有点像分治法,把一大堆数据分成若干个桶,每个桶内各自排序,最后再合并。

桶排序的一个要点就是如何确定桶的数量和桶与桶之间的跨度,在上面我看的程序员小灰的文章中他是创建与原始数组长度数量相等的桶,除了最后一个桶只包含一个最大值之外,其余各桶之间的区间跨度=(最大值-最小值)/(桶数量-1)。

假如有一个这样的数组:

[3.31, 2.26, 3.94, 3.67, 4.96, 2.12, 3.91, 3.72, 0.12, 3.2, 0.01, 3.5, 2.78, 1.21, 2.97, 2.64]

一共有 16 个元素,所以我们创建 16 个桶。最大值为 4.96,最小值为 0.01,所以每个桶之间的跨度为 (4.96-0.01)/(16-1)=0.33。

然后遍历原始数组,将各元素放到对应的桶中:

然后各个桶内各自排序:

最后遍历输出桶内元素即可。

3 代码实现

    @Test
    public void testBucketSort() {
        double[] doubleArray = new double[new Random().nextInt(10) + 10];
        for (int i = 0; i < doubleArray.length; i++) {
            double random = new Random().nextDouble();
            if (random > 0.5) {
                random -= 0.5;
            }
            doubleArray[i] = random * 10;
            doubleArray[i] = Double.valueOf(String.format("%.2f", doubleArray[i]));
        }
        bucketSort(doubleArray);
    }

    public static double[] bucketSort(double[] origin) {
        if (origin == null || origin.length == 0) {
            return new double[]{};
        }
        System.out.println("origin--->" + Arrays.toString(origin));
        // 获取数组中最大值、最小值
        double max = origin[0];
        double min = origin[0];
        for (int i = 0; i < origin.length; i++) {
            if (origin[i] > max) {
                max = origin[i];
            }
            if (origin[i] < min) {
                min = origin[i];
            }
        }
        System.out.println("max--->" + max);
        System.out.println("min--->" + min);
        System.out.println("origin.length--->" + origin.length);
        // 创建桶,数量与原始数组的长度相同
        ArrayList<LinkedList<Double>> bucketList = new ArrayList<>();
        for (int i = 0; i < origin.length; i++) {
            bucketList.add(new LinkedList<>());
        }
        // 每个桶的区间跨度
        double span = (max - min) / (origin.length - 1);
        System.out.println("span--->" + span);
        // 将数据放到对应桶,最后一个桶永远只会存在一个元素,就是最大值
        for (int i = 0; i < origin.length; i++) {
            int bucketIndex = (int) ((origin[i] - min) / span);
            bucketList.get(bucketIndex).add(origin[i]);
        }
        System.out.println("bucketList--->" + bucketList);
        // 将每个桶内部排序,Collections.sort() 底层使用的是归并排序
        for (int i = 0; i < bucketList.size(); i++) {
            Collections.sort(bucketList.get(i));
        }
        System.out.println("bucketList--->" + bucketList);
        // 遍历桶,所有元素已经从小到大排序号,输出所有元素即可
        double[] sortedArray = new double[origin.length];
        int index = 0;
        for (List<Double> bucket : bucketList) {
            for (Double d : bucket) {
                sortedArray[index++] = d;
            }
        }
        System.out.println("sortedArray--->" + Arrays.toString(sortedArray));
        return origin;
    }

结果如下:

4 总结

时间复杂度

假设原始数列有 n 个元素,分成 m 个桶,第一步求最大最小值时间复杂度为 O(n);第二步创建空桶时间复杂度为 O(m);第三步遍历原始数组时间复杂度为 O(n);第四步桶内各元素排序,归并排序时间复杂度为 O(nlogn),所以时间复杂度为 O(n/m*log(n/m)*m);第五步输出结果时间复杂度为 O(n),总的时间复杂度为 O(3n+m+n/m*log(n/m)*m)。去掉系数的话时间复杂度为 O(n+m+n(logn-logm))。

控件复杂度

假设原始数列有 n 个元素,分成 m 个桶,空间复杂度为 O(m+n)。

优点

1.当桶内元素分布均匀时,即 n=m 时,时间复杂度为 O(n)。

2.可以对小数进行排序。

缺点

1.当桶内元素分布极不均匀时时间复杂度为 O(nlogn),还会创建许多空桶,造成空间浪费。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值