优先队列介绍:
优先队列(priority queue)可以在 O(1) 时间内获得最大值,并且可以在 O(log n) 时间内取出
最大值或插入任意值。
优先队列常常用堆(heap)来实现。堆是一个完全二叉树,其每个节点的值总是大于等于子
节点的值。实际实现堆时,我们通常用一个数组而不是用指针建立一个树。这是因为堆是完全二
叉树,所以用数组表示时,位置 i 的节点的父节点位置一定为 i/2,而它的两个子节点的位置又一
定分别为 2i 和 2i+1。
以下是堆的实现方法,其中最核心的两个操作是上浮和下沉:如果一个节点比父节点大,那
么需要交换这个两个节点;交换后还可能比它新的父节点大,因此需要不断地进行比较和交换操
作,我们称之为上浮;类似地,如果一个节点比父节小,也需要不断地向下进行比较和交换操作,
我们称之为下沉。如果一个节点有两个子节点,我们总是交换最大的子节点。
题目:
给定 k 个增序的链表,试将它们合并成一条增序链表。
思路:
把所有的链表存储在一个优先队列中,每次提取所有链表头部节点值最小的那个节点,直到所有链表都被提取完为止。注意因为 Comp 函数默认是对最大堆进行比较并维持递增关系,如果我们想要获取最小的节点值,则我们需要实现一个最小堆,因此比较函数应该维持递减关系,所以 operator() 中返回时用大于号而不是等增关系时的小于号进行比较。
class Solution {
class Status implements Comparable<Status> {
int val;
ListNode ptr;
Status(int val, ListNode ptr) {
this.val = val;
this.ptr = ptr;
}
public int compareTo(Status status2) {
return this.val - status2.val;
}
}
PriorityQueue<Status> queue = new PriorityQueue<Status>();
public ListNode mergeKLists(ListNode[] lists) {
for (ListNode node: lists) {
if (node != null) {
queue.offer(new Status(node.val, node));
}
}
ListNode head = new ListNode(0);
ListNode tail = head;
while (!queue.isEmpty()) {
Status f = queue.poll();
tail.next = f.ptr;
tail = tail.next;
if (f.ptr.next != null) {
queue.offer(new Status(f.ptr.next.val, f.ptr.next));
}
}
return head.next;
}
}