Java排序算法 [堆排序]

本文详细介绍了一种高效的排序算法——堆排序。通过构建最大堆并逐步调整堆结构来完成排序过程,实现了平均时间复杂度为O(n log n)的排序效率。文章通过具体的代码示例解释了堆排序的基本原理及其实现细节。

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

package cn.com.dom4j.sort;

import java.util.Arrays;

public class Test2 {

    /**
     * 堆排序
     */
    public static <AnyType extends Comparable<? super AnyType>> void heapSort(AnyType[] a) {

        // buildHeap
        for (int i = a.length / 2; i >= 0; i--) {
            // 将数组值按初始顺序放入堆中, 从根节点执行下滤操作将构建一个堆
            percolateDown(a, i, a.length);
        }

        // deleteMax
        for (int i = a.length - 1; i > 0; i--) {
            // 在构建了一个 max堆后, 将根节点与最后一个元素互换, 同时将堆的大小 -1, 调整位置, 再次实现堆序
            // 这样每互换一次, 最大的元素就会放在堆的后面 (已经从堆中删除, 不属于堆了), 堆后面的元素会保持顺序, 直到堆中只剩一个元素为止
            swap(a, 0, i);
            percolateDown(a, 0, i);
        }

    }

    /**
     * 下滤操作: 调整某个节点的位置, 以保持堆序
     * @param a 待排序序列
     * @param i 要调整的节点在数组中的索引
     * @param n 堆的大小 (堆中元素个数)
     */
    private static <AnyType extends Comparable<? super AnyType>> void percolateDown(AnyType[] a, int i, int n) {

        int child;
        AnyType tmp;

        // tmp记录被调整元素的值, i的值随 child不断改变, 直到比较完所有的子节点 (leftChild(i) < n) 为止
        for (tmp = a[i]; leftChild(i) < n; i = child) {
            child = leftChild(i);
            // child == n - 1时, 其左子节点为堆的最后一个元素, 没有右节点, 无须比较
            // 将该节点与其左右节点比较, 记录其中最小的节点的索引
            if (child != n - 1 && a[child].compareTo(a[child + 1]) < 0) {
                child++;
            }
            // 将需要被调整和节点与其子节点进行比较, 如果小于子节点, 当前节点的值替换为子节点的值 (注意不是交换)
            if (tmp.compareTo(a[child]) < 0) {
                a[i] = a[child];
            } else {
                break;
            }
        }
        // 找到合适的位置后, 直接赋值来避免多余的交换操作
        a[i] = tmp;
    }

    /**
     * 获取某个节点的左子节点在数组中的索引, 因为是从 0开始的, 所以要 +1
     */
    private static int leftChild(int i) {
        return 2 * i + 1;
    }


    /**
     * 交换数组中两个元素的位置
     */
    public static <AnyType extends Comparable<? super AnyType>> void swap(AnyType[] arr, int i, int j) {
        if (arr == null || arr.length <= 1 || i == j) {
            return;
        }

        AnyType tmp = arr[i];
        arr[i] = arr[j];
        arr[j] = tmp;
    }
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值