【经典排序算法】9. 桶排序

桶排序,将待排序数据平均切分为几个区间(不同的区间之间本身就是有序的),叫做桶,每个桶各自将元素排序好,再将桶内数据合并即可完成排序。桶排序必须将数据均匀分布在桶中,如果数据全在一个桶中,排序会退化为桶内的排序类型。

计数排序可以看做是一种极端的桶排序,一个数就对应一个桶,一个桶只存放一个具体的数(而不是一个区间的数)。

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

public class Main {
    public static void main(String[] args) {
        int[] arr = {3, 5, 6, 2, 1, 7, 4};
        System.out.print("排序前:");
        arrPrint(arr);
        int[] result = BucketSort(arr, 4);
        System.out.print("排序后:");
        arrPrint(result);
    }

    // 桶排序
    // bucketsize用于定义桶排序时候桶的size/长度,分配的桶数量则为(max - min)/bucketsize + 1
    // 实例中bucketsize设为4,桶数量bucketnum则为2。
    //
    //
    // 最大最小值max和min初始化为arr的第一个元素,遍历arr元素,把总是比max大的数赋给max,
    // 把总是比min小的数赋给min。得到arr中的最大最小值max和min。
    //
    // 计算桶数量bucketnum = (max - min)/bucketsize + 1,桶排序是将待排序数组arr
    // 中的元素,平均切分到 bucketnum 这么多个区间的排序,因此max-min计算区间范围长度,
    // 在本实例中max-min=6,÷桶的长度bucketsize=4,再+1即可得到bucketnum=2(除法+1,相
    // 当于除法的余数向上取整)。
    // (参考计数排序中,利用-min操作,将arr[i]∈[min,max]映射到方便从0索引的
    // arr[i]-min∈[0,max-min]的操作,桶排序的桶区间元素同样如此)
    //
    // 利用ArrayList数据类型开辟桶空间buckets,容量声明为bucketnum。
    // 第一个for循环,遍历buckets,索引从0遍历到bucketnum,在buckets开辟的空间中
    // 填入ArrayList<Integer>,作为桶空间来存储元素(并排序)。bucketnum为2就填入2个
    // ArrayList<Integer>。
    //
    // 第二个for循环,遍历arr的元素,利用arr[i]-min的映射,将arr[i]∈[min,max]的分布,
    // 映射到 arr[i]-min∈[0,max-min]的分布,方便我们利用桶索引来对应元素。
    // 同时由于[0,max-min]已经被buckets切分为 bucketnum=2 份了,
    // 所以(arr[i]-min)/bucketsize 得到的除数正好可以作为桶索引bkindex,
    // 本实例中第一个bucketsize的范围是[0,bucketsize - 1],第二个桶的范围
    // 是[bucketsize, max - min]。如果(arr[i]-min)/bucketsize除数为0,
    // 说明arr[i]应该放入第一个桶,以此类推。得到桶索引bkindex后利用ArrayList
    // get方法取得桶,add方法将元素放入桶即可:buckets.get(bkindex).add(arr[i])
    //
    // 第三个for循环,对每个桶各自使用排序(这里使用Collections的自带排序)。
    //
    // 第四个for循环组,for双循环,第一个for,索引为i,顺序遍历buckets的每一个桶
    // buckets.get(i)。第二个for,索引为j,顺序遍历每个桶中的每一个元素(已被排序)
    // buckets.get(i).get(j),元素存入result中即可。
    // 最后返回result。
    // 注:查看桶情况可插入 System.out.println(buckets.toString()) 来打印桶
    private static int[] BucketSort(int[] arr, int bucketsize) {
        int max = arr[0];
        int min = arr[0];
        for (int num: arr) {
            if (max < num)
                max = num;
            if (min > num)
                min = num;
        }
        int bucketnum = (max - min) / bucketsize + 1;
        ArrayList<ArrayList<Integer>> buckets = new ArrayList<>(bucketnum);
        for (int i = 0; i < bucketnum; i++) {
            buckets.add(new ArrayList<Integer>());
        }

        for (int i = 0; i < arr.length; i++) {
            int bkindex = (arr[i] - min) / bucketsize;
            buckets.get(bkindex).add(arr[i]);
        }

        for (int i = 0; i < buckets.size(); i++) {
            Collections.sort(buckets.get(i));
        }

        int index = 0;
        int[] result = new int[arr.length];
        for (int i = 0; i < buckets.size(); i++) {
            for (int j = 0; j < buckets.get(i).size(); j++) {
                result[index++] = buckets.get(i).get(j);
            }
        }
        return result;
    }

    // 辅助函数:将int[] 打印出来
    private static void arrPrint(int[] arr) {
        StringBuilder str = new StringBuilder();
        str.append("[");
        for (int v : arr) {
            str.append(v + ", ");
        }
        str.delete(str.length() - 2, str.length());
        str.append("]");
        System.out.println(str.toString());
    }
}

该实例的动画演示如下:

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/fisherish/article/details/114479002