【数据结构】Java实现各类经典排序算法——桶排序、堆排序

本文详细介绍了两种排序算法——桶排序与堆排序。桶排序适用于特定数据分布情况,通过将数据分配到多个桶中进行计数排序。堆排序则通过构建大顶堆并逐步移除最大元素完成排序。两者在不同场景下各有优势。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、桶排序

    桶排序作为非通用的排序算法,桶的数量要根据原数组中元素大小分布来确定。为方便说明和测试,此处以LeetCode75——Sort Colors的题目为代码环境。

    题目大意:原数组包含若干个0、1、2,对原数组进行排序。

    1. 创建大小为3的数组(3个桶),各元素初始值为0。数组第1、2、3位的值分别代表原数组中0、1、2的数目;

    2. 扫描原数组,更新各桶的值;

    3. 扫描各桶,更新排序原数组。

    以下为代码实现:

    public void bucketSort(int[] nums) {
        // 桶排序
        int buckets[] = new int[3];
        for(int item : nums) {
            buckets[item]++;
        }
        int cursor = 0;
        for(int bucket = 0; bucket < buckets.length; bucket++) {
            for(int i = 0; i < buckets[bucket]; i++) {
                nums[cursor] = bucket;
                cursor++;
            }
        }
    }

    时间复杂度:O(n+r),n为原数组元素个数,r为桶的个数;空间复杂度:O(r),即桶的个数,也就是桶数组的大小。


二、堆排序

    堆排序在经典排序算法里算是比较复杂的了。算法分为两个部分:

    1. 对原始数组建立大顶堆;

    2. 删除堆顶元素,在数组中从右往左放置,再更新堆的结构和大小。(可以避免引入新的缓存数组)

    在这种策略下,堆排序的空间复杂度仅为O(1),而时间复杂度在最好、最坏、平均情况下均为O(nlogn)。此时看来优于快速排序、归并排序(快排空间复杂度为O(logn)且最坏时间复杂度为O(n2),归并排序空间复杂度为O(n))。但堆排序和快排一样是不稳定的(比如原始数组为[6, 6, 6],天然大顶堆,删除堆顶也就是最左边的6时,该6会被放到最右边去),因此Java自带的Sort是用归并排序为主体算法。

    以下为算法实现代码:

    public void heapSort(int[] nums) {
        buildMaxHeap(nums);  // 建立大顶堆
        for(int i = nums.length - 1; i > 0; i--) { 
            swap(nums, 0, i);  // 大顶堆最大数换到数组最右,次大换到次右,以此类推
            downPerco(nums, 0, i);  // 每换一次,堆的大小减一并重新下滤树根
        }
    }
    
    public void buildMaxHeap(int[] nums) {
        for(int i = nums.length / 2 - 1; i >= 0; i--) {
            downPerco(nums, i, nums.length);
        }
    }
    
    public void downPerco(int[] nums, int item, int n) {
        int tmp = nums[item];
        while(item <= n / 2 - 1) { // 有儿子
            int child = 2 * item + 1;  //左儿子
            if(child < n - 1 && nums[child] < nums[child + 1]) { // 如果有右儿子且右儿子更大,则右儿子是大儿子
                child++;
            }
            if(nums[child] > tmp) { // 如果大儿子大过祖宗,就继续往下走;否则终止
                nums[item] = nums[child];
                item = child;
            } else {
                break;
            }
        }
        nums[item] = tmp;
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值