排序--10---桶排序

Posted 高高for 循环

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了排序--10---桶排序相关的知识,希望对你有一定的参考价值。

桶排序(Bucket Sort)

定义:

  • 桶排序(Bucketsort)或所谓的箱排序,是一个排序算法,工作的原理是将数组分到有限数量的桶里。每个桶再个别排序(有可能再使用别的排序算法或是以递归方式继续使用桶排序进行排序),最后依次把各个桶中的记录列出来记得到有序序列。
  • 桶排序是鸽巢排序的一种归纳结果。当要被排序的数组内的数值是均匀分配的时候,桶排序使用线性时间(Θ(n))。但桶排序并不是比较排序,他不受到O(nlog n)下限的影响

区分计数排序

桶排序 是计数排序的升级版。它利用了函数的映射关系,高效与否的关键就在于这个映射函数的确定。
  • 桶排序是计数排序的扩展版本,计数排序可以看成每个桶只存储相同元素,而桶排序每个桶存储一定范围的元素,通过映射函数,将待排序数组中的元素映射到各个对应的桶中,对每个桶中的元素进行排序,最后将非空桶中的元素逐个放入原序列中。
  • 桶排序需要尽量保证元素分散均匀,否则当所有数据集中在同一个桶中时,桶排序失效。

原理:

桶排序的思想近乎彻底的分治思想

  • 步骤1:人为设置一个BucketSize,作为每个桶所能放置多少个不同数值(
  • 步骤2:遍历输入数据,并且把数据一个一个放到对应的桶里去;
  • 步骤3:对每个不是空的桶进行排序,可以使用其它排序方法,也可以递归使用桶排序;
  • 步骤4:从不是空的桶里把排好序的数据拼接起来。

映射函数:

  1. 在额外空间充足的情况下,尽量增大桶的数量
  2. 使用的映射函数能够将输入的 N 个数据均匀的分配到 K 个桶中

如果我们桶的数量太多,就比如说有MAX-MIN+1个桶:那么很显然这时候的桶排序又重新退化成了我们上面刚刚讲解过的计数排序了.

比较 排序算法:

同时,对于桶中元素的排序,选择何种比较排序算法对于性能的影响至关重要

图解:

假设就设置5个桶

代码实现 1

import java.util.ArrayList;
import java.util.Collections;

public class BucketSort01 {
    public static void Sort(int[] arr){

        // 计算最大值与最小值
        int max = Integer.MIN_VALUE;
        int min = Integer.MAX_VALUE;
        for(int i = 0; i < arr.length; i++){
            max = Math.max(max, arr[i]);
            min = Math.min(min, arr[i]);
        }

        // 计算桶的数量
        int bucketNum = (max - min) / arr.length + 1;
        ArrayList<ArrayList<Integer>> bucketArr = new ArrayList<>(bucketNum);
        for(int i = 0; i < bucketNum; i++){
            bucketArr.add(new ArrayList<Integer>());
        }

        // 将每个元素放入桶
        for(int i = 0; i < arr.length; i++){
            int num = (arr[i] - min) / (arr.length);
            bucketArr.get(num).add(arr[i]);
        }

        // 对每个桶进行排序
        for(int i = 0; i < bucketArr.size(); i++){
            Collections.sort(bucketArr.get(i));
        }

        // 将桶中的元素赋值到原序列
        int index = 0;
        for(int i = 0; i < bucketArr.size(); i++){
            for(int j = 0; j < bucketArr.get(i).size(); j++){
                arr[index++] = bucketArr.get(i).get(j);
            }
        }
    }

    public static void main(String[] args) {
        int[] data = { 9, 5, -1, 8, 11, 3, 7, -3, 50, 3 };
        System.out.println("排序之前:\\n" + java.util.Arrays.toString(data));
        Sort(data);
        System.out.println("排序之后:\\n" + java.util.Arrays.toString(data));
    }

}

Java 中的Arrays.sort()方法

Collections.sort()实际是调用的Java 中的Arrays.sort()

Jdk中的Arrays.sort()的实现是通过所谓的双轴快排的算法

算法分析

  • 桶排序最好情况下使用线性时间O(n),桶排序的时间复杂度,取决与对各个桶之间数据进行排序的时间复杂度,因为其它部分的时间复杂度都为O(n)。很显然,桶划分的越小,各个桶之间的数据越少,排序所用的时间也会越少。但相应的空间消耗就会增大。

时间复杂度:

对于待排序序列大小为 N,共分为k 个桶,主要步骤有:

  • N 次循环,将每个元素装入对应的桶中
  • k 次循环,对每个桶中的数据进行排序(平均每个桶有 N/M 个元素)

桶排序的时间复杂度和上面的计数排序是一样的,同样也是线性级别的,但是也是增加了桶的时间,所以也是O(n+k)

- 最佳时间复杂度:O(n + k)

- 最差时间复杂度:O(n ^ 2)

- 平均时间复杂度:O(n + k) 稳定

空间复杂度:

  • 上面我们已经说过了,桶排序本身也是一个通过空间来换取时间的算法,所以很明显他的空间复杂度就会很高.并且这个空间复杂度主要就取决于桶的数量以及桶的范围,所以假设有k个桶的话,那么空间复杂度就为O(n+k)
  • 空间复杂度就为O(n+k)

小结:

  • 桶排序是计数排序的变种,它利用了函数的映射关系,高效与否的关键就在于这个映射函数的确定。把计数排序中相邻的m个”小桶”放到一个”大桶”中,在分完桶后,对每个桶进行排序(一般用快排),然后合并成最后的结果。
  • 算法思想和散列中的开散列法差不多,当冲突时放入同一个桶中;可应用于数据量分布比较均匀,或比较侧重于区间数量时。
  • 桶排序最关键的建桶,如果桶设计得不好的话桶排序是几乎没有作用的。通常情况下,上下界有两种取法,第一种是取一个10^n 或者是 2^n 的数,方便实现。另一种是取数列的最大值和最小值然后均分作桶.

以上是关于排序--10---桶排序的主要内容,如果未能解决你的问题,请参考以下文章

排序--10---桶排序

《数据结构与算法之美》10——排序桶排序计数排序基数排序

桶排序——基数排序

桶排序,计数排序算法

桶排序

桶排序之基数排序