排序 之 桶数组-Java

本文详细介绍了桶排序算法,包括简单版和复杂版的实现。简单桶排序通过新建数组,利用数值作为下标进行计数排序;复杂版则使用ArrayList作为桶,将数据按范围分到不同桶中再排序。讨论了算法的时间复杂度和空间复杂度,并提出了一种通过减去最小值优化桶数量的方法。此外,还对比了两种桶排序在不同场景下的适用性。
摘要由CSDN通过智能技术生成

桶数组排序,是一种空间换时间的算法。
简单的桶数组排序,要新建一个数组,其大小是待排序数字的最大值+1;
复杂的桶数组排序,是一个集合中放好多桶数组,计算桶的数组的数量,分别将一定范围的值放到桶数组中。

简单的桶数组排序

这种比较好理解,思路是《啊哈算法》算法书中的,作者也说真正的桶排序算法比这个难的多,但这种简单的更适合入门。

思路及步骤结合下图说明:
对于放着 5, 3,5,2,8 数组arr进行排序:

第一步:遍历数组arr,找到待排序数组中的最大值max;
第二步:新建一个数组,空间比最大值max大一些;
第三步:遍历待排序的数组arr,将数值做为新数组arr2的下标,进行自加;
第四步:遍历新数组arr2,哪个大于1就输出该处下标即可。

解释:第三步走完,如下图,arr2中,arr2[2],ar2r[3],arr2[8]处的值分别是1,arr[5]处的值是2,
然后进行第四步,遍历数组arr2,遇到不为0的就打印下标,就可以完成排序。

在这里图来自《啊哈算法》图片描述
图来自《啊哈算法》

代码实现:

/**
 * @Description: 桶数组排序,简单的
 */
public class BucketSort {
    public static void main(String[] args) {
        //调用方法测试
        int arr[] = {5, 3, 5, 2, 8};
        bucketSort(arr);
    }

    //桶数组排序
    public static void bucketSort(int arr[]){
        int len = arr.length;

        //找到数组中最大值
        int max = Integer.MIN_VALUE; //-2147483648
        for (int i = 0; i < len; i++){
            max = Math.max(arr[i], max);
        }

        //新建一个数组,空间为原数据最大值+1(这也是桶数组的缺点)
        int arr2[] = new int[max+1];

        //遍历待排序的数组,将数值做为新数组的下标,进行自加
        for (int i = 0; i < len; i++){
            arr2[arr[i]]++;
        }
        
		//遍历输出
        for (int i = 0; i < max+1; i++){ //依次遍历数组arr2,
            for (int j = 1; j <= arr2[i]; j++){ //出现几次就将桶的编号输出几次
                System.out.println(i);
            }
        }
    }
}

时间复杂度:
时间复杂度(平均): O(n)
时间复杂度(最坏): O(nlog2n)
空间复杂度 : O(m)
稳定性:稳定

优化: 在我跟同学说完这个简单的桶排序后,他说了一种优化一些的方法,很厉害,
意思是: 将待排序的数组,都减去最小值,这样就能减少桶数量,遍历输出时,再加上最小值就可以了。
这种比较适合 各个相差比较小 的数据,这样能极大地减少桶数量。
下边复杂的桶数组排序,比较适合散列大一点的,能够很好地减少空间。

复杂的桶数组排序

这种是一个集合中,放入好多桶,将一定范围的待排序放入桶中,然后对桶中数据进行排序,最后依次输出桶中数据即可。
思路及步骤结合下图说明:

第一步:找出待排序数组中的最大值max和最小值min;
第二步:使用ArrayList做为桶,然后里面还放ArrayList桶,大小为:(max-min)/arr.length+1;
第三步:遍历待排序的数组,将数据放到桶中;
第四步:将各个桶中数据进行排序;
第五步:遍历桶数组,输出。

在这里插入图片描述
(图来自网络,图中的桶数和代码计算不太一样)

代码实现

public class BucketSort2 {
    public static void main(String[] args) {

        int arr2[] = {18, 11, 28, 45, 23, 50};
        bucketSort(arr2);
        System.out.println(Arrays.toString(arr2));
    }

    //桶数组排序
    public static void bucketSort(int arr[]) {
        if (arr == null || arr.length == 0) {
            return;
        }

        //计算最大值与最小值:将数组的值与最大、最小比较获得
        int max = Integer.MIN_VALUE; //-2147483648
        int min = Integer.MAX_VALUE; // 2147483647
        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;
        System.out.println("bucketNum:" + bucketNum);
        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));
            System.out.println(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);
            }
        }
    }
}

时间复杂度
当输入的元素是0到k之间的整数时
平均时间复杂度:O(n + k)
最佳时间复杂度:O(n + k)
最差时间复杂度:O(n ^ 2)
空间复杂度:O(n * k)
稳定性:稳定
桶排序最好情况下使用线性时间O(n),桶排序的时间复杂度,取决与对各个桶之间数据进行排序的时间复杂度,因为其它部分的时间复杂度都为O(n)。很显然,桶划分的越小,各个桶之间的数据越少,排序所用的时间也会越少。但相应的空间消耗就会增大。

常用的方法
length —— 数组的属性;
length() —— String的方法;
size() —— 集合的方法;

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值