使用最小堆合并 K 个已排序链表的Java程序 – 第 2 组
给定k个大小为n的链表,每个链表按非降序排序,将它们合并为一个排序(非降序)链表,并将排序后的链表打印为输出。
例子:
Input: k = 3, n = 4
list1 = 1->3->5->7->NULL
list2 = 2->4->6->8->NULL
list3 = 0->9->10->11->NULL
Output: 0->1->2->3->4->5->6->7->8->9->10->11
Merged lists in a sorted order
where every element is greater
than the previous element.
Input: k = 3, n = 3
list1 = 1->3->7->NULL
list2 = 2->4->8->NULL
list3 = 9->10->11->NULL
Output: 1->2->3->4->7->8->9->10->11
Merged lists in a sorted order
where every element is greater
than the previous element.
资料来源:合并 K 排序的链表 |方法二
这篇文章的方法 3中讨论了该问题的有效解决方案。
方法:此解决方案基于用于解决此处讨论的“合并 k 个排序数组”问题的MIN HEAP方法。
MinHeap: Min-Heap 是一棵完全二叉树,其中每个内部节点中的值都小于或等于该节点子节点中的值。将堆的元素映射到数组中很简单:如果一个节点存储在索引 k 处,那么它的左子节点存储在索引 2k + 1 处,其右子节点存储在索引 2k + 2 处。
- 创建一个最小堆并插入所有“k”链表的第一个元素。
- 只要 min-heap 不为空,请执行以下步骤:
- 删除最小堆的顶部元素(这是最小堆中所有元素中的当前最小值)并将其添加到结果列表中。
- 如果在上一步弹出的元素旁边存在一个元素(在同一个链表中),则将其插入最小堆。
- 返回合并列表的头节点地址。
下面是上述方法的实现:
Java
// Java implementation to merge
// k sorted linked lists
// Using MIN HEAP method
import java.util.PriorityQueue;
import java.util.Comparator;
public class MergeKLists
{
// Function to merge k sorted
// linked lists
public static Node mergeKSortedLists(
Node arr[], int k)
{
Node head = null, last = null;
// priority_queue 'pq' implemeted
// as min heap with the
// help of 'compare' function
PriorityQueue pq =
new PriorityQueue<>(new Comparator()
{
public int compare(Node a, Node b)
{
return a.data - b.data;
}
});
// Push the head nodes of all
// the k lists in 'pq'
for (int i = 0; i < k; i++)
if (arr[i] != null)
pq.add(arr[i]);
// Loop till 'pq' is not empty
while (!pq.isEmpty())
{
// Get the top element of 'pq'
Node top = pq.peek();
pq.remove();
// Check if there is a node
// next to the 'top' node
// in the list of which 'top'
// node is a member
if (top.next != null)
// push the next node in 'pq'
pq.add(top.next);
// if final merged list is empty
if (head == null)
{
head = top;
// Points to the last node so far
// of the final merged list
last = top;
}
else
{
// Insert 'top' at the end of the
// merged list so far
last.next = top;
// Update the 'last' pointer
last = top;
}
}
// Head node of the required merged list
return head;
}
// Function to print the singly linked list
public static void printList(Node head)
{
while (head != null)
{
System.out.print(head.data + " ");
head = head.next;
}
}
// Utility function to create
// a new node
public Node push(int data)
{
Node newNode = new Node(data);
newNode.next = null;
return newNode;
}
public static void main(String args[])
{
// Number of linked lists
int k = 3;
// Number of elements in each list
int n = 4;
// An array of pointers storing the
// head nodes of the linked lists
Node arr[] = new Node[k];
arr[0] = new Node(1);
arr[0].next = new Node(3);
arr[0].next.next = new Node(5);
arr[0].next.next.next = new Node(7);
arr[1] = new Node(2);
arr[1].next = new Node(4);
arr[1].next.next = new Node(6);
arr[1].next.next.next = new Node(8);
arr[2] = new Node(0);
arr[2].next = new Node(9);
arr[2].next.next = new Node(10);
arr[2].next.next.next = new Node(11);
// Merge all lists
Node head = mergeKSortedLists(arr, k);
printList(head);
}
}
class Node
{
int data;
Node next;
Node(int data)
{
this.data = data;
next = null;
}
}
// This code is contributed by Gaurav Tiwari
输出:
0 1 2 3 4 5 6 7 8 9 10 11
复杂性分析:
- 时间复杂度: O(N * log k) or O(n * k * log k),其中,'N'是所有链表中元素的总数,'k'是链表的总数,' n' 是每个链表的大小。
所有N个节点的插入和删除操作都会在min-heap中进行。
最小堆中的插入和删除需要 log k 时间。 - 辅助空间: O(k)。
优先级队列在任何时间点最多有“k”个元素,因此我们的算法所需的额外空间是 O(k)。
请参阅有关合并 k 排序链表的完整文章 |设置 2(使用最小堆)了解更多详情!