PriorityQueue底层是基于数组实现的二叉小顶堆,满足完全二叉树结构约束:节点i的父节点在(i−1)/2,左孩子在2i+1,右孩子在2i+2;插入时上浮调整、删除时下沉调整,核心操作时间复杂度为O(log n)。

PriorityQueue 底层是二叉小顶堆,用数组模拟完全二叉树,不是链式二叉树。它不保证整体有序,只保证堆顶最小(小顶堆)或最大(大顶堆),每次 poll() 取出的是当前最小元素,offer() 插入后自动调整结构维持堆序。这种设计让它特别适合动态维护“当前最小/最大”这一类需求,比如任务调度、Top-K、合并K个有序链表等场景。
小顶堆的结构与索引关系
数组下标从 0 开始时:
- 节点 i 的左孩子在
2*i + 1 - 右孩子在
2*i + 2 - 父节点在
(i - 1) / 2(整除)
这个映射让父子关系可直接计算,无需指针,空间紧凑。所有操作都基于这个隐式结构做上浮(插入时)或下沉(删除时)调整。
核心操作的时间复杂度
关键在于单次调整最多走树高,而完全二叉树高度为 ⌊log₂n⌋ + 1,即 O(log n):
-
offer(E e):元素插入末尾,然后向上调整(siftUp)。最坏从叶到根,O(log n) -
poll():取堆顶,用末尾元素补空位,再向下调整(siftDown)。最坏从根到叶,O(log n) -
peek():仅返回queue[0],O(1) -
remove(Object o):先遍历找位置(O(n)),再用末尾元素填补并双向调整(O(log n)),合计 O(n)
建堆的两种方式与时间差异
初始化含 n 个元素的 PriorityQueue 时,有两种常见路径:
- 逐个 offer:相当于 n 次插入,每次 O(log k),k 从 1 增至 n → 总时间 O(n log n)
- 批量建堆(heapify):从最后一个非叶子节点倒序向下调整。数学推导证明总比较次数为 O(n),实际实现也按此优化 → O(n)
Java 的 PriorityQueue(Collection c) 构造器就用了 heapify,比循环 add 快一个数量级。
空间复杂度与稳定性说明
PriorityQueue 是基于动态数组(Object[] queue)实现的,初始容量 11,扩容策略类似 ArrayList(1.5 倍)。所以:
- 空间复杂度始终是 O(n),无额外递归栈或指针开销
- 它不保证相等元素的相对顺序,属于不稳定排序结构 —— 这和堆本身不记录插入次序有关,调整过程可能打乱同优先级元素的位置

















