Java PriorityQueue(优先级队列/二叉堆):默认是小顶堆
PriorityQueue
优先队列PriorityQueue是Queue接口的实现,可以对其中元素进行排序,可以放基本数据类型的包装类(如:Integer,Long等)或自定义的类
- 对于基本数据类型的包装器类,优先队列中元素默认排列顺序是升序排列
- 对于自己定义的类来说,需要自己定义比较器
在构造器中可以传入一个比较器
1. 优先队列遍历
PriorityQueue的iterator()不保证以任何特定顺序遍历队列元素。若想按特定顺序遍历,先将队列转成数组,然后排序遍历
2. PriorityQueue有几个需要注意的点:
- 不允许加入 Null 对象
- 添加到PriorityQueue的对象必须具有可比性
- 比较器Comparator可用于队列中对象的自定义排序(升序/降序,自定义参与比较的是对象的哪个变量)
- PriorityQueue是一个无限制的队列,并且动态增长。默认初始容量’11’可以使用相应构造函数中的initialCapacity参数覆盖
- 如果存在多个具有相同优先级的对象,则它可以随机轮询其中任何一个
- PriorityQueue 不是线程安全的。PriorityBlockingQueue在并发环境中使用
- 它为add/offer和remove/poll方法提供了O(log(n))时间
3. LeetCode 相关习题
23. 合并 K 个升序链表
- 用容量为K的最小堆优先队列,把链表的头结点都放进去,然后出队当前优先队列中最小的,挂上链表
- 然后让出队的那个节点的下一个入队,再出队当前优先队列中最小的,直到优先队列为空
class Solution {
public ListNode mergeKLists(ListNode[] lists) {
if (lists == null){
return null;
}
PriorityQueue<ListNode> queue = new PriorityQueue<ListNode>(new Comparator<ListNode>() {
@Override
public int compare(ListNode o1, ListNode o2) {
return o1.val - o2.val;
}
});
for (ListNode node : lists) {
if (node != null){
queue.offer(node);
}
}
ListNode dummyNode = new ListNode(-1);
ListNode cur = dummyNode; // 指针
while (!queue.isEmpty()){ // 小顶堆【每次弹出的都是最小的!!!】
ListNode node1 = queue.poll();
cur.next = node1;
if (node1.next != null){
queue.offer(node1.next);
}
cur = cur.next;
}
return dummyNode.next;
}
}
215. 数组中的第 k 个最大元素
第 k 个最大 ===> 有 k - 1 个元素比你小 ===> 构造大小为 k 的小顶堆
当新加入的 > 堆顶
- poll
- offer(新加入的)
class Solution {
public int findKthLargest(int[] nums, int k) {
Queue<Integer> queue = new PriorityQueue<>(); // 维护一个大小为 k 的小顶堆
for (int i = 0; i < k; i++) {
queue.add(nums[i]);
}
for (int i = k; i < nums.length; i++) {
if (nums[i] > queue.peek()){
queue.poll();
queue.offer(nums[i]);
}
}
return queue.peek();
}
}
703. 数据流中的第 k 大元素
class KthLargest {
// 维护一个大小为 k 的小顶堆,新加入一个元素和堆顶比较
// 1. 如果比堆顶小,丢弃
// 2. 如果比堆顶大,删除堆顶元素,加入新的 val
PriorityQueue<Integer> queue; // 优先级队列
int size; // 堆的大小
public KthLargest(int k, int[] nums) { // 初始化
queue = new PriorityQueue<>(k);
size = k;
for (int num : nums) {
add(num);
}
}
public int add(int val) { // 插入数据流 num 后,返回当前数据流中第 k 大的元素
if (queue.size() < size){ // 优先级队列未满
queue.offer(val);
}else {
if (queue.peek() < val){ // peek < val,弹出堆顶,压入新值
queue.poll();
queue.offer(val);
}
}
return queue.peek();
}
}