Java中的优先队列PriorityQueue
PriorityQueue
是 Java 里的 “优先队列”——
本质上是一个 二叉堆(binary heap),默认 小根堆(堆顶最小)。
它 不是普通 FIFO 队列,而是 每次取出的都是“优先级最高”的元素。
1 基本定位
接口/类 | 说明 |
---|---|
实现接口 | Queue , Collection , Iterable |
底层结构 | 对象数组 实现的 可扩容二叉堆(完全二叉树) |
是否线程安全 | ❌ 非同步;需要并发请用 PriorityBlockingQueue |
允许 null | ❌ 插入 null 抛 NullPointerException |
是否有序 | 整体 无序;只有 堆顶 是最小(或最大) |
2 默认小根堆
PriorityQueue<Integer> q = new PriorityQueue<>();
q.add(5);
q.add(1);
q.add(3);
System.out.println(q.poll()); // 1
System.out.println(q.poll()); // 3
System.out.println(q.poll()); // 5
每次 poll()
都会拿出 当前最小值。
3 自定义排序:改成“大根堆”
// 方法 1:传入 Comparator
PriorityQueue<Integer> maxHeap = new PriorityQueue<>((a, b) -> b - a);// 方法 2:使用 Comparator.reverseOrder()
PriorityQueue<Integer> maxHeap2 = new PriorityQueue<>(Comparator.reverseOrder());
4 核心 API
方法 | 功能 | 失败时行为 |
---|---|---|
boolean offer(E e) | 入堆 | 返回 false / 抛异常(视容量策略) |
E peek() | 看堆顶 | 空返回 null |
E poll() | 弹出堆顶 | 空返回 null |
boolean remove(Object o) | 删除指定元素 | 成功 true,否则 false |
int size() | 当前元素个数 | |
clear() / contains() | 同 Collection |
5 存储结构:数组表示完全二叉树
对于下标 i(从 0 开始)
- 父节点索引:
(i - 1) / 2
- 左孩索引:
2*i + 1
- 右孩索引:
2*i + 2
堆化向上(siftUp
)与向下(siftDown
)时间复杂度 O(log n)。
6 初始容量与扩容
- 默认初始容量 11
- 扩容策略:旧容量 < 64 时 2 倍 + 2;否则 1.5 倍
- 可显式指定容量
new PriorityQueue<>(initialCapacity)
7 元素必须可比较
元素要么
- 实现
Comparable<T>
(自然顺序), - 或在构造时提供
Comparator<? super E>
。
否则运行期抛 ClassCastException
。
8 与 TreeSet 的异同
特性 | PriorityQueue | TreeSet |
---|---|---|
底层 | 二叉堆 | 红黑树 |
整体有序 | ❌ 只有堆顶最值 | ✅ 完全有序 |
时间复杂度 | offer/poll O(log n) | add/remove O(log n) |
重复元素 | ✅ 允许 | ❌ 不允许 |
9 常见用途
- Top-K 问题(用容量固定为 K 的大/小根堆)
- 合并 K 个有序链表/数组
- Dijkstra、Prim 等图算法需要“当前最小边/节点”
- 定时任务调度(DelayQueue 内部也用优先队列)
10 小结一句话
PriorityQueue = 可动态增删的“堆”结构,永远把“优先级最高”的元素放在队首,默认小根堆,自定义 Comparator 可变大根堆,操作复杂度 O(log n)。