Heap简介

概念

堆是一种基于完全二叉树的数据结构,其中每个父节点都大于等于/小于等于其子节点。可以分为最大堆(Max Heap)和最小堆(Min Heap),其中最大堆要求父节点的值大于或等于所有子节点,而最小堆要求父节点的值小于或等于所有子节点。

特点

  • 使用数组实现:通过利用数组索引表示完全二叉树中元素之间关系来节省内存空间。
  • 快速查找:插入、删除和获取操作具有对数时间复杂度。
  • 动态扩展:能够自动调整大小以容纳更多元素。

优点

  1. 高效插入和删除操作:插入和删除具有对数时间复杂度。
  2. 高效获取最大/最小元素:可以快速获取具有极端值的顶部元素。

缺点

  1. 不支持随机访问:堆不同于数组或链表,无法直接通过索引访问特定位置上的元素。
  2. 中间位置元素难以访问和更新:要查找、更新或删除非顶部位置上的元素会变得复杂且低效。

适用场景

  • 需要快速获取最大/最小元素的场景。
  • 常用于优先队列、排序算法(如堆排序)等领域。

示例代码

下面是一个以最大堆为例的java代码简单实现:

import java.util.Arrays;
import java.util.NoSuchElementException;

class Heap {
    private int[] heapArray;
    private int maxSize;
    private int currentSize;

    public Heap(int size) {// 构造函数,创建一个具有指定大小的堆对象。
        this.maxSize = size;
        this.currentSize = 0;
        this.heapArray = new int[size];
    }

    public boolean isEmpty() {// 检查堆是否为空,并返回布尔值。
        return currentSize == 0;
    }

    public boolean isFull() {// 检查堆是否已满,并返回布尔值。
        return currentSize == maxSize;
    }

    public void insert(int value) {// 向堆中插入一个元素。如果堆已满,则抛出异常。该方法使用“上溯”操作来维护堆性质。
        if (isFull()) {
            throw new IllegalStateException("Heap is full");
        }

        heapArray[currentSize] = value;

        trickleUp(currentSize);

        currentSize++;
    }

    private void trickleUp(int index) {//从给定索引开始执行上溯操作以维护堆性质。它将当前节点与其父节点进行比较和交换,直到达到合适的位置或达到根节点为止。
        int parentIndex = (index - 1) / 2; // 计算父节点索引

        while (index > 0 && heapArray[parentIndex] < heapArray[index]) {
            // 交换父节点与子节点的值
            int temp = heapArray[parentIndex];
            heapArray[parentIndex] = heapArray[index];
            heapArray[index] = temp;

            index = parentIndex;
            parentIndex = (index - 1) / 2; // 更新父节点索引
        }
    }

    public int remove() {// 移除并返回顶部(最大)元素。如果堆为空,则抛出异常。该方法使用“下溯”操作来维护堆性质。
        if (isEmpty()) {
            throw new IllegalStateException("Heap is empty");
        }

        int root = heapArray[0]; // 根节点的值为最大/最小元素

        currentSize--;

        heapArray[0] = heapArray[currentSize];

        trickleDown(0);

        return root;
    }

    private void trickleDown(int index) {// 从给定索引开始执行下溯操作以维护堆性质。它将当前节点与其较大子节点进行比较和交换,直到没有子节点或找到合适的位置为止。
        int largerChildIndex;

        while (index < currentSize / 2) { // 判断是否有子节点
            int leftChildIndex = 2 * index + 1;
            int rightChildIndex= leftChildIndex + 1;

            if (rightChildIndex < currentSize &&
                    heapArray[leftChildIndex] <heapArray[rightChildIndex]) {
                largerChildIndex=rightChildIndex;
            } else{
                largerChildIndex=leftChildIndex ;
            }

            if(heapArray[index]>=heapArray[largerChildIndex]){
                break;   // 当前位置已满足堆性质,不需要调整,退出循环
            }

            swap(index, largerChildIndex);
            index=largerChildIndex;//更新索引以继续下一轮比较
        }
    }


    private void swap(int index1,int index2){ //用于交换数组中两个索引位置上的元素。
        int temp=heapArray[index1];
        heapArray[index1]=heapArray[index2];
        heapArray[index2] = temp;
    }

    public int[] getHeapArray() {// 返回堆中所有元素
        return Arrays.copyOf(heapArray, currentSize);
    }

    public int peek() {// 查看但不删除顶部元素
        if (currentSize == 0) {
            throw new NoSuchElementException("Heap is empty.");
        }

        return heapArray[0];
    }
}

public class Main {
    public static void main(String[] args) {
        //创建一个最大堆
        Heap heap = new Heap(10);

        // 插入元素
        heap.insert(80);
        heap.insert(75);
        heap.insert(60);
        heap.insert(68);
        heap.insert(55);

        // 打印堆中所有元素
        System.out.println("Current elements in the heap: " + Arrays.toString(heap.getHeapArray()));

        // 获取并移除顶部(最大)元素
        int maxElement=heap.remove();
        System.out.println("Maximum element removed from the heap: "+maxElement);


        //打印删除顶部元 素后的堆
        System.out.println("Current elements in the heap after removal:" + Arrays.toString(heap.getHeapArray()) );

        //插入新元素
        heap.insert(100);

        //查看但不删除顶部元素
        maxElement=heap.peek();
        System.out.println("Maximum element removed from the heap: "+maxElement);

        //打印堆中所有元素
        System.out.println("Current elements in the heap: " + Arrays.toString(heap.getHeapArray()));
    }
}

常见问题

  1. 元素大小问题:在构建或插入时,需要确保父节点与子节点具有正确的大小关系。如果使用自定义对象作为堆中的元素,请实现正确的比较器来定义大小关系。
  2. 动态调整容量:如果底层数组满了,则需要进行动态扩展以容纳更多的元素。这可能涉及重新分配内存和复制数据,并带来一些性能开销。
  3. 并发问题:Java提供了线程安全的优先队列实现,如PriorityBlockingQueue。如果在多线程环境中使用,请确保选择适当的实现以避免并发问题。

总结

堆是一种基于完全二叉树的数据结构,通过父节点与子节点之间的比较来维护其特性。它支持快速插入、删除和获取最大/最小元素的操作,并用于优先队列和排序算法(如堆排序)等场景。处理大小关系、动态调整容量和并发问题时要注意正确性和性能。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Heapanalyzer是一种用于分析Java堆转储文件的强大工具,由IBM开发。它可以帮助我们找到可能的内存泄漏点。使用Heapanalyzer的步骤如下: 1. 首先,需要获取一个Java堆转储文件。这个文件通常是在发生内存溢出(OOM)错误时生成的。可以通过设置JVM参数,使其在发生OOM时生成堆转储文件。 2. 下载并安装HeapAnalyzer。可以从IBM官方网站上下载安装包。 3. 打开HeapAnalyzer。在界面上选择“File”菜单,然后选择“Open Heap Dump”选项。 4. 在打开堆转储文件对话框中,选择要分析的堆转储文件,并点击“打开”。 5. Heapanalyzer会开始分析堆转储文件。分析完成后,会显示一个树形结构的对象列表,显示了堆中的各个对象及其关系。 6. 可以使用Heapanalyzer提供的各种功能来进一步分析堆转储文件。例如,可以查找对象的引用链,查看对象的详细信息,查找可能的内存泄漏等。 需要注意的是,Heapanalyzer只是一个工具,它可以帮助我们找到可能的内存泄漏点,但真正的内存溢出问题还需要结合程序来进行进一步的分析。因此,在使用Heapanalyzer时,我们还需要结合其他工具和技术来进行全面的内存分析和调试。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [IBM heapAnalyzer分析dump文件](https://blog.csdn.net/qq_36908872/article/details/124061972)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 50%"] - *2* *3* [IBM HeapAnalyzer简介使用](https://blog.csdn.net/wwd0501/article/details/78657319)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大宝贱

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值