动画:一篇文章快速学会桶排序

内容介绍

桶排序简介

前面学过计数排序,计数排序是一个非基于比较的排序算法,它的优点在于在对必定范围内的整数排序时,它的复杂度为Ο(n+k)。java

所谓桶就是存放多个数据的容器,桶排序也是非基于比较的排序算法,将待排序数据按照必定的规则存放到对应的桶中,再进行排序与合并。桶排序能够对必定范围内的数据包括小数进行排序。桶排序能够突破基于比较排序算法的时间复杂度O(nlogn)。算法

桶排序的思想

将待排序数据分配到有限数量的桶里。每一个桶再单独进行子排序,最后按顺序将多个桶中的数据进行合并,排序完成。当待排序的数组内的数值是均匀分配的时候,桶排序的时间复杂度为O(n)。编程

桶排序动画演示

假设有10我的给某个商品进行评分,评分的范围是0~1之间的小数,例如{0.6, 0.85, 0.9, 0.5, 0.35, 0.2, 0.1, 0.85, 0.8, 0.5} 这10个数据。通常没有特殊要求排序算法都是升序排序,小的在前,大的在后,效果以下: 数组

桶排序分析

经过上面动画能够看出桶排序分为4个步骤:微信

  1. 划分合适数量的桶。
  2. 将全部待排序数据放入到对应的桶中。
  3. 使用合理的算法对每一个非空桶进行子排序。
  4. 按顺序将每一个桶中数据进行合并。

第一步:划分合适数量的桶动画

关于如何划分合适数量的桶,根据不一样规模和不一样范围的数据,咱们采起不一样的划分方式。目前数据都是0到1之间小数,数据比较均匀,咱们等分红4个桶,每一个桶的范围都是0.25,效果以下: 3d

第二步:将全部待排序数据放入到对应的桶中code

遍历待排序数据,将每一个数据放入对应范围的桶中,效果以下: blog

第三步:使用合理的算法对每一个非空桶进行子排序排序

待排序数据划分到不一样桶中后,每一个桶中的数据仍是无序的,以下图所示: 从上图能够看到,第二个桶不用排序,其余桶须要进行排序,分别对每一个桶中的数据再使用合适的排序算法,好比快速排序。排序后效果以下图:

第四步:4.按顺序将每一个桶中数据进行合并

合并前效果以下图: 如今范围小的桶在前面,范围大的桶在后面,而且每一个桶中的数据也是从小到大排序的,所以咱们只须要从左往右将每一个桶中的数据取出放到数组中便可。取出第一个桶后的数据以下: 取出第二个桶后的数据以下:

取出第三个桶后的数据以下:

取出第四个桶后的数据以下:

当全部桶中的数据都取出后排序就完成了。

桶排序代码编写

public class BucketSort {
    public static void main(String[] args) {
        double[] arr = {0.6, 0.85, 0.9, 0.5, 0.35, 0.2, 0.1, 0.85, 0.8, 0.5};

        bucketSort(arr);

        System.out.println("排序后: " + Arrays.toString(arr));
    }

    public static void bucketSort(double[] arr) {
        // 获取最大值和最小值
        double max = arr[0];
        double min = arr[0];
        for (int i = 1; i < arr.length; i++) {
            double num = arr[i];
            if (num > max)
                max = num;
            else if (num < min)
                min = num;
        }

        // 桶的数量
        int bucketNumber = 4;

        // 每一个桶的范围
        double range = (max - min) / bucketNumber;

        // 1.初始化全部桶,每一个桶都是LinkedList,方便增长数据
        LinkedList<Double>[] buckets = new LinkedList[bucketNumber];
        for (int i = 0; i < buckets.length; i++) {
            buckets[i] = new LinkedList<>();
        }

        // 2.将全部待排序数据放入到对应的桶中
        for (int i = 0; i < arr.length; i++) {
            double num = arr[i];
            int index = (int) ((num - min) / range);
            if (index == bucketNumber)
                index -= 1; // 若是这个数字正好是最大值,计算出索引就是number,会数组越界,放到最后一个桶中
            buckets[index].add(num);
        }

        // 3.使用合理的算法对每一个非空桶进行子排序
        for (int i = 0; i < buckets.length; i++) {
            // 对每一个桶中的数据进行排序
            Collections.sort(buckets[i]);
        }

        // 4.按顺序将每一个桶中数据进行合并
        int index = 0;
        for (int i = 0; i < buckets.length; i++) {
            LinkedList<Double> bucket = buckets[i];
            for (int j = 0; j < bucket.size(); j++) {
                arr[index] = bucket.get(j);
                index++;
            }
        }
    }
}

桶排序的局限性

若是数据通过桶的划分以后,有些桶里的数据很是多,有些很是少,很不平均,那桶内数据排序的时间复杂度就不是常量级了。在极端状况下,若是数据都被划分到一个桶里,桶排序就退化为O(nlogn)的排序算法,以下图所示: 桶排序对待排序数据的要求是很是苛刻的,适用场景是在数据分布相对比较均匀或者数据跨度范围并非很大时。若是数据跨度很是大,空间消耗就会很大。因此桶排序不多使用。

桶排序比较适合用在外部排序中

所谓的外部排序就是数据存储在外部磁盘中、数据量比较大、内存有限,没法将数据所有加载到内存中。好比说咱们有50GB的订单数据,咱们但愿按订单金额进行排序,可是咱们的内存有限只有几GB,没办法一次性把50GB的数据都加载到内存中。假设订单金额最小是0.1元,最大是10万元。能够将全部订单根据金额划分到100个桶里,第一个桶存储金额在0.1元到100元以内的订单,第二桶存储金额在101元到200元以内的订单,依次类推。每个桶对应一个文件。订单金额在0.1元到10万元之间并不必定是均匀分布的,因此50GB订单数据是没法均匀地被划分到100个文件中的。有可能某个金额区间的数据特别多,划分以后对应的文件很大,无法一次性读入内存,针对某些划分以后仍是比较大的文件,咱们能够继续划分,好比订单金额在0.1元到100元之间的比较多,咱们就将这个区间继续划分为10个小区间,0.1元到10元,11元到20元,21元到30元依次类推,而后将每一个桶对应的数据读取到内存中使用快速排序进行排序,结果保存在文件中,最后合并到已排序的文件中。

桶排序的复杂度

  1. 空间复杂度:数据规模为n,划分到k个桶中,总空间复杂度O(n + k)
  2. 时间复杂度:1.获取最大值和最小值,遍历数组,操做次数为n。2.初始化全部桶,操做次数为k。3.将全部待排序数据放入到对应的桶中操做次数为n。4.每一个非空桶进行子排序使用时间复杂度为O(nlogn)的快速排序总操做次数为(k/n)*log(k/n)*k。5.按顺序将每一个桶中数据进行合并操做次数n。因此总的时间复杂度为:3n+k+(k/n)*log(k/n)*k,所以时间复杂度为:O(n+k+logn-logk)
  3. 稳定性:稳定

总结

桶排序也是非基于比较的排序算法,将待排序数据按照必定的规则存放到对应的桶中,再进行排序与合并。桶排序能够对必定范围内的数据包括小数进行排序。桶排序能够突破基于比较排序算法的时间复杂度O(nlogn)。

桶排序的思想:将待排序数据分配到有限数量的桶里。每一个桶再单独进行子排序,最后按顺序将多个桶中的数据进行合并,排序完成。当要被排序的数组内的数值是均匀分配的时候,桶排序的时间复杂度为O(n)。

桶排序对待排序数据的要求是很是苛刻的,适用场景是在数据分布相对比较均匀或者数据跨度范围并非很大时。若是数据跨度很是大,空间消耗就会很大,若是数据都被划分到一个桶里,桶排序就退化为O(nlogn)的排序算法,因此桶排序不多使用。

桶排序比较适合用在外部排序中。


原创文章和动画制做真心不易,您的点赞就是最大的支持! 想了解更多文章请关注微信公众号:表哥动画学编程

相关文章
相关标签/搜索