1. 什么是堆?
堆(Heap)是一种特殊的完全二叉树,分为两类:
- 大顶堆(Max Heap): 父节点值 >= 子节点值,堆顶是最大值。
- 小顶堆(Min Heap): 父节点值 <= 子节点值,堆顶是最小值。
堆的常见应用包括优先队列、动态最大/最小值维护、贪心算法等。
2. 大顶堆 vs 小顶堆
类型 | 规则 | 取出元素 | 适用场景 |
---|---|---|---|
大顶堆 | 父节点值 ≥ 子节点值 | 最大值 | 需要动态维护最大值,如第 K 大元素、贪心算法 |
小顶堆 | 父节点值 ≤ 子节点值 | 最小值 | 需要动态维护最小值,如最小代价合并、最短路径 |
3. Java 实现堆(PriorityQueue
)
Java 的 PriorityQueue
默认是小顶堆(最小值优先):
PriorityQueue<Integer> minHeap = new PriorityQueue<>(); // 小顶堆
PriorityQueue<Integer> maxHeap = new PriorityQueue<>((a, b) -> b - a); // 大顶堆
3.1 堆的常见操作
操作 | 复杂度 | 说明 |
---|---|---|
插入 (offer ) | O(log n) | 插入后上浮 |
取堆顶 (peek ) | O(1) | 直接返回堆顶元素 |
删除堆顶 (poll ) | O(log n) | 取出最大/最小元素后下沉 |
建堆 | O(n) | 一次性建堆比单个插入更快 |
4. 堆的应用场景
4.1 动态维护 K 个最大/最小值
- 大顶堆:求第 K 大元素
- 小顶堆:维护前 K 大元素,堆顶是第 K 大元素
4.2 贪心算法
- 大顶堆:每次选择当前范围内最优解
- 小顶堆:合并代价最小的方案
4.3 滑动窗口最大值
- 大顶堆:维护窗口内最大值
4.4 堆排序(HeapSort)
- 时间复杂度 O(n log n),不稳定排序。
- 适用于不想修改原数组的情况。
5. 堆 vs 队列 vs 栈
数据结构 | 特性 | 取元素 | 适用场景 |
---|---|---|---|
队列(Queue) | FIFO(先进先出) | 按入队顺序 | BFS、任务调度 |
栈(Stack) | LIFO(后进先出) | 栈顶元素 | DFS、括号匹配 |
堆(Heap) | 动态排序 | 最大/最小值优先 | 优先队列、贪心算法、动态最值维护 |
5.1 Java 中的三种数据结构定义
// 队列(先进先出)
Queue<Integer> queue = new LinkedList<>();
queue.offer(1);
int first = queue.poll();
// 栈(后进先出)
Stack<Integer> stack = new Stack<>();
stack.push(1);
int top = stack.pop();
// 堆(优先队列)
PriorityQueue<Integer> minHeap = new PriorityQueue<>(); // 小顶堆
PriorityQueue<Integer> maxHeap = new PriorityQueue<>((a, b) -> b - a); // 大顶堆
6. 总结
- 堆是一种特殊的完全二叉树,用于动态维护最大/最小值。
- Java 的
PriorityQueue
默认是小顶堆,需要自定义比较器实现大顶堆。 - 堆的常见操作是插入(O(log n))、删除堆顶(O(log n))、取堆顶(O(1))。
- 堆常用于贪心、动态 K 大/最小元素、滑动窗口最大值、排序等。