JAVA中的堆

本文深入探讨了堆数据结构的原理与应用,包括大堆和小堆的概念,堆的调整操作及其时间复杂度,以及如何通过堆实现优先队列。此外,还介绍了Java标准库中优先队列的使用方法,展示了如何自定义比较器以改变队列的排序方式。

1.堆

堆实际上就是用数组将一个完全二叉树存起来,堆的主要用途就是用来找集合中的最大值和最小值,也可以解决top-K问题,就是类似找出第一最大值,第二最大值。。。。

1》堆可以分为:大堆和小堆
大堆:树中的任意节点,节点值必须大于左右孩子的值
小堆:树中的任意节点,节点值必须小于左右孩子的值

2》堆的调整操作:
向上调整(除根结点外,其他结点都符合堆的要求)对象:大堆小堆

private   void shiftUp(int[] array,int size,int index) {
        int child = index;
        int parent = (child-1)/2;
        while (child > 0) {
            if (array[parent]<array[child]) {
                int tmp = array[parent];
                array[parent] = array[child];
                array[child] = tmp;
            }else {
                break;
            }
            child = parent;
            parent = (child-1)/2;


        }
    }

时间复杂度:O(logN)
向下调整(除孩子结点,其他结点都符合堆的要求)对象:大堆小堆

 public static void shiftDown(int[] array,int size,int index) {
        int parent = index;
        int child = 2*parent+1;
        while (child<size) {
            if (child+1<size&&array[child+1]>array[child]) {
                child = child+1;
            }
            if (array[child]>array[parent]) {
                int tmp = array[child];
                array[child] = array[parent];
                array[parent] = tmp;
            }else {
                break;
            }
            parent = child;
            child = 2*parent+1;
        }
    }

时间复杂度:O(logN)

3》建堆(时间复杂度:O(N))
基于向下调整建堆必须从后往前遍历数组
基于向上调整建堆必须从前往后遍历数组

   public static void createHeap(int[] array,int size) {
        for (int i = (size-1-1)/2;i>=0;i--) {
            shiftDown(array,size,i);
        }
    }

2.用堆创建的优先队列

1》入队列

 public void offer(int x) {
        array[size] = x;
        size++;
        shiftUp(array,size,size-1);
    }

直接插到数组最后,然后向上调整成大堆

2》出队列

public Integer poll() {
        if (size <= 0) {
            return null;
        }
        int ret = array[0];
        array[0] = array[size-1];
        size--;
        shiftDown(array,size,0);
        return ret;
    }

即将数组第一个元素取出并删除还要保持剩下的结点是一个堆,用新的变量保存根节点,然后将最后一个元素赋值给第一个,然后size–将最后一个元素删除,在从0号元素进行向下调整就可以保证剩下元素是堆,然后返回新的变量,最大值就取到了。

3》取队首元素

public Integer peek() {
        if (size == 0) {
            return null;
        }
        return array[0];
    }

3.标准库中的优先队列

import java.util.Comparator;
import java.util.PriorityQueue;


// 标准库中的优先队列默认为小堆

public class TestPriorityQueue {
//自定义优先级
    static class MyComp implements Comparator<Integer> {
        public int compare(Integer o1,Integer o2) {

            return o2-o1;
        }
    }
    public static void main(String[] args) {
        PriorityQueue<Integer> queue = new PriorityQueue<>(new MyComp());
        queue.offer(9);
        queue.offer(5);
        queue.offer(2);
        queue.offer(7);
        queue.offer(3);
        queue.offer(6);
        queue.offer(8);
        while (!queue.isEmpty()) {
            Integer cur = queue.poll();
            System.out.println(cur);
        }

    }
}

标准库中的优先队列默认是小堆,即最小的优先权最高,我们可以通过定义这个比较器来修改输出顺序。

### Java 内存详解 #### 1. 内存的作用与重要性 Java内存是Java虚拟机(JVM)所管理的内存中最重要的部分之一。程序运行期间创建的所有对象都存储在此处[^1]。由于几乎所有的应用程序都会频繁地分配和释放对象,因此内存的有效管理和优化对于应用性能至关重要。 #### 2. 内存结构 通常情况下,JVM将划分为新生代(Young Generation),老年代(Tenured/Old Generation)[^1]: - **新生代**:主要用于存放新创建的对象实例以及生命周期较短的小型临时对象; - **老年代**:当某些对象经过多次GC周期后仍然存活,则会被移动到老年代; 这种分代设计有助于提高垃圾收集效率,因为大多数对象都是短暂存在的,只有少数会长期存在并最终进入老年代。 #### 3. 常见的内存问题及其解决方案 ##### OutOfMemoryError: Java Heap Space 如果尝试为新对象分配更多空间时发现当前可用的容量不足,便会抛出`java.lang.OutOfMemoryError: Java heap space`异常。这可能是由于设置了过低的最大大小(-Xmx参数), 或者确实存在内存泄漏等问题所致[^2]。 为了防止此类错误的发生,可以通过调整JVM启动参数适当增加最大允许使用的尺寸: ```bash java -Xms512m -Xmx4g MyApplication ``` 上述命令表示初始最小设置为512MB, 最大可达4GB. ##### GC Overhead Limit Exceeded 另一个常见的问题是`java.lang.OutOfMemoryError: GC overhead limit exceeded`, 它表明虽然进行了大量的垃圾回收工作,但能够获得的空间却非常有限。此时应该考虑是否存在大量难以被清理掉的大对象或者循环引用关系阻止了正常回收过程. 针对这种情况建议采取措施减少不必要的长期持有对象,并定期分析heap dump文件查找潜在的问题根源。 #### 4. 方法区与其他非内存区域简介 除了之外,JVM还维护着其他几个重要的内存区域,比如方法区(Method Area)用于保存已加载类的数据; 还有直接缓冲池(Direct Buffer Pool)属于操作系统层面而非严格意义上的JVM内部组成部分,但它同样受到总物理RAM数量的影响并且可能触发OOM错误][^[^34]. 通过理解这些不同类型的内存布局可以帮助开发者更好地诊断复杂的应用场景下的各种内存相关难题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

lhj_loveFang_1105

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

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

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

打赏作者

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

抵扣说明:

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

余额充值