当前位置: 首页 > news >正文

JAVA中的堆和栈

在 Java 中,“堆” 和 “栈” 有两层含义:一是JVM 内存模型中的堆(Heap)和栈(Stack),二是数据结构中的堆(Heap)和栈(Stack)。而 “优先队列(PriorityQueue)” 是基于数据结构中的堆实现的高级容器。下面从这两个维度分别总结,并结合使用方法和案例说明。

一、JVM 内存模型中的堆与栈

这是 Java 内存管理的核心概念,与对象存储、内存分配直接相关。

1. 堆(Heap)
  • 概念:JVM 中最大的内存区域,线程共享,用于存储所有对象实例(包括数组)和字符串常量池(JDK7 后移至堆)。
  • 特性
    • 动态分配内存,大小可通过 JVM 参数(如-Xms-Xmx)调整。
    • 内存回收由垃圾回收器(GC)自动管理,无需手动释放。
    • 分配速度较慢(需处理内存碎片、GC 等),但存储容量大。
2. 栈(Stack,虚拟机栈)
  • 概念:线程私有,每个线程对应一个虚拟机栈,由多个栈帧组成(每个方法调用对应一个栈帧)。
  • 特性
    • 存储局部变量(基本类型、对象引用)、方法返回地址、操作数栈等。
    • 遵循 “后进先出(LIFO)” 原则,方法调用时入栈,执行完毕后出栈。
    • 内存自动分配和释放(随方法调用 / 结束),速度快,无内存碎片。
3. 核心区别与使用场景
维度堆(JVM)栈(JVM)
线程共享性共享(所有线程可访问)私有(仅当前线程访问)
存储内容对象实例、字符串常量池局部变量、方法栈帧
内存管理垃圾回收器自动回收随方法调用 / 结束自动释放
速度较慢较快

案例:变量存储位置

public class MemoryDemo {// 成员变量(存储在堆中,随对象实例存在)private String heapVar = "堆中的字符串";public void method() {// 局部变量(基本类型,存储在栈中)int stackVar = 10;// 对象引用(引用存栈中,对象实例存堆中)String ref = new String("栈中引用,堆中对象");}
}

二、数据结构中的栈(Stack)

数据结构中的栈是一种线性表,仅允许在一端(栈顶)进行插入和删除操作,遵循 “后进先出(LIFO)” 原则。

1. 常用实现与方法

Java 中不推荐使用java.util.Stack(继承Vector,线程安全导致性能开销),推荐用Deque接口的ArrayDeque实现(更高效)。

核心方法:

  • push(E e):入栈(添加元素到栈顶)。
  • pop():出栈(移除并返回栈顶元素,栈空时抛异常)。
  • poll():出栈(移除并返回栈顶元素,栈空时返回null)。
  • peek():查看栈顶元素(不移除)。
  • isEmpty():判断是否为空。
2. 使用案例:逆波兰表达式求值

逆波兰表达式(后缀表达式)是运算符在操作数后的表达式,适合用栈计算结果。

import java.util.Deque;
import java.util.ArrayDeque;public class RPNCalculator {public static int evalRPN(String[] tokens) {Deque<Integer> stack = new ArrayDeque<>();for (String token : tokens) {if (token.equals("+") || token.equals("-") || token.equals("*") || token.equals("/")) {// 弹出两个操作数计算int b = stack.pop();int a = stack.pop();switch (token) {case "+": stack.push(a + b); break;case "-": stack.push(a - b); break;case "*": stack.push(a * b); break;case "/": stack.push(a / b); break;}} else {// 数字入栈stack.push(Integer.parseInt(token));}}return stack.pop();}public static void main(String[] args) {String[] tokens = {"2","1","+","3","*"}; // 等价于 (2+1)*3System.out.println(evalRPN(tokens)); // 输出 9}
}

三、数据结构中的堆(Heap)

数据结构中的堆是一种完全二叉树,分为两种:

  • 最大堆:父节点值 ≥ 子节点值(堆顶为最大值)。
  • 最小堆:父节点值 ≤ 子节点值(堆顶为最小值)。

Java 中无直接的Heap类,通过PriorityQueue间接实现堆功能(默认是最小堆)。

1. 常用方法(基于PriorityQueue
  • offer(E e):添加元素并调整堆结构(维持堆特性)。
  • poll():移除并返回堆顶元素(最小 / 最大值),自动调整堆。
  • peek():查看堆顶元素(不移除)。
  • size():返回元素个数。
2. 堆的创建方式
  • 最小堆(默认):new PriorityQueue<>()
  • 最大堆:new PriorityQueue<>(Collections.reverseOrder())
  • 自定义排序:传入Comparator,如new PriorityQueue<>((a, b) -> b - a)(最大堆)。
3. 使用案例:查找数据流中的中位数

用两个堆(一个最大堆存较小一半元素,一个最小堆存较大一半元素)动态维护中位数。

import java.util.*;public class MedianFinder {private PriorityQueue<Integer> maxHeap; // 存较小的一半(堆顶为最大值)private PriorityQueue<Integer> minHeap; // 存较大的一半(堆顶为最小值)public MedianFinder() {maxHeap = new PriorityQueue<>(Collections.reverseOrder());minHeap = new PriorityQueue<>();}public void addNum(int num) {// 先加入最大堆,再平衡两个堆的大小maxHeap.offer(num);minHeap.offer(maxHeap.poll());// 保证最大堆 size ≥ 最小堆 size(最多差1)if (maxHeap.size() < minHeap.size()) {maxHeap.offer(minHeap.poll());}}public double findMedian() {if (maxHeap.size() > minHeap.size()) {return maxHeap.peek(); // 奇数个元素,最大堆顶为中位数} else {return (maxHeap.peek() + minHeap.peek()) / 2.0; // 偶数个,取平均}}public static void main(String[] args) {MedianFinder finder = new MedianFinder();finder.addNum(1);finder.addNum(2);System.out.println(finder.findMedian()); // 1.5finder.addNum(3);System.out.println(finder.findMedian()); // 2.0}
}

四、优先队列(PriorityQueue)

优先队列是一种特殊队列,元素按优先级排序,每次出队的是优先级最高的元素(底层基于堆实现)。

1. 核心特性
  • 排序规则:默认按元素自然顺序(Comparable),或通过Comparator自定义。
  • 无序性:迭代器遍历不保证顺序,仅poll()/peek()能获取优先级最高的元素。
  • 时间复杂度:插入(offer)和删除(poll)为O(log n),查询堆顶为O(1)
2. 使用案例:合并 K 个有序链表

利用优先队列每次取出最小节点,高效合并多个有序链表。

import java.util.*;// 链表节点定义
class ListNode {int val;ListNode next;ListNode(int val) { this.val = val; }
}public class MergeKLists {public ListNode mergeKLists(ListNode[] lists) {if (lists == null || lists.length == 0) return null;// 优先队列(按节点值升序,每次取最小节点)PriorityQueue<ListNode> pq = new PriorityQueue<>(Comparator.comparingInt(a -> a.val));// 初始化:将每个链表的头节点加入队列for (ListNode node : lists) {if (node != null) pq.offer(node);}ListNode dummy = new ListNode(0);ListNode cur = dummy;// 循环取最小节点,拼接结果链表while (!pq.isEmpty()) {ListNode minNode = pq.poll();cur.next = minNode;cur = cur.next;// 若当前节点有下一个节点,加入队列if (minNode.next != null) {pq.offer(minNode.next);}}return dummy.next;}
}

五、总结

概念本质 / 核心特性典型使用场景
JVM 堆线程共享,存储对象实例,GC 管理对象创建、长生命周期数据存储
JVM 栈线程私有,存储局部变量和方法帧,LIFO方法调用、临时变量存储
数据结构栈LIFO 线性表,仅栈顶操作括号匹配、表达式求值、递归模拟
数据结构堆完全二叉树,最大 / 小堆,动态取最值Top K 问题、中位数查找、优先级调度
优先队列(PriorityQueue)基于堆实现,按优先级出队任务调度、合并有序数据、事件触发机制

http://www.dtcms.com/a/549491.html

相关文章:

  • A2A协议的多智能体投顾引擎架构, 智能体生成年化418%,回撤11%,夏普比5.19的规则策略,附python代码
  • 建设黑彩网站需要什么药理学网站建设方案
  • Linux本机ping虚机ip Network unreachable
  • 个体工商户可以备案哪些网站做一个同城便民信息网站怎么做
  • 队列——速成
  • 南京建设网站的公司网易企业邮箱登录入口手机
  • R语言基于Rselenium模拟浏览器抓取DatabaseCommons数据-连载NO.04
  • 对于一些MP4文件的压缩
  • 基于Selenium和AI的图像处理
  • Selenium Wire 网络拦截实现方案
  • 无锡手机网站制作费用网页设计与网站建设在线考试
  • 【Qt】【1. 版本特性介绍】
  • pyside6的历史发展、Qt 介绍、PyQt 和 pyside6对比
  • 做没用的网站建立个网站
  • numpy的random函数总结
  • ⸢ 拾-Ⅱ⸥⤳ 威胁感知与响应建设方案:威胁运营威胁响应
  • Auto Dark Mode,一款Windows 自动深浅色切换工具
  • 惠民县建设网站信宜网站设计公司
  • 论文对应项目复现教程
  • 第165期 无需提示词的微调:Bonepoke 与系统姿态的隐藏调控旋钮
  • 口腔种植中叠腮技术的适应证与考量
  • 原码、反码、补码与正数、负数的运算关系介绍
  • ShimetaPi丨事件相机新版SDK发布:支持Python调用,可降低使用门槛
  • 计算机图形学:【Games101】学习笔记03——光栅化(三角形的离散化、深度测试与抗锯齿)
  • 如何掌握【Java】 IO/NIO设计模式?工厂/适配器/装饰器/观察者模式全解析
  • C# 中的空条件运算符(?.)与空合并运算符(??)详解
  • 福建人力资源建设网站房地产销售技巧
  • 佳木斯 网站建设网页版qq登录入口版qq账号登录界面
  • 基于django网站开发课设报告广州开公司的基本流程及费用
  • VecDeque 的环形缓冲区:从 `head/tail` 到 `wrapping_add`,一次把缓存、SIMD 与 `no_std` 全部打通