合并 K 个排序链表
给定 K 个大小为 N 的已排序链表,任务是将它们全部合并并保持其排序顺序。
例子:
输入:K = 3,N = 4
list1 = 1->3->5->7->NULL
list2 = 2->4->6->8->NULL
list3 = 0->9->10->11->NULL
输出:0->1->2->3->4->5->6->7->8->9->10->11
按排序顺序合并列表,其中每个元素都大于等于前一个元素。
输入:K = 3,N = 3
list1 = 1->3->7->NULL
list2 = 2->4->8->NULL
list3 = 9->10->11->NULL
输出:1->2->3->4->7->8->9->10->11
按排序顺序合并列表,其中每个元素都大于等于前一个元素。
书接上回 合并 k 个排序链表 (1)。
使用最小堆合并 K 个排序链表
请按照给定的步骤解决问题:
- 创建一个最小堆并插入所有链表的第一个元素。
- 只要min-heap不为空,就执行以下步骤:
- 删除最小堆的根(这是最小堆中所有元素中当前的最小值)并将其添加到结果列表中。
- 如果上一步弹出的元素后边存在一个元素(在同一个链表中),则将其插入到最小堆中。
- 返回合并链表的头节点地址。
下面是上述方法的实现:
C++
// C++ implementation to merge k
// sorted linked lists
// Using MIN HEAP method
#include <bits/stdc++.h>
using namespace std;
struct Node
{
int data;
struct Node* next;
};
// Utility function to create
// a new node
struct Node* newNode(int data)
{
// Allocate node
struct Node* new_node = new Node();
// Put in the data
new_node->data = data;
new_node->next = NULL;
return new_node;
}
// 'compare' function used to build
// up the priority queue
struct compare
{
bool operator()(
struct Node* a, struct Node* b)
{
return a->data > b->data;
}
};
// Function to merge k sorted linked lists
struct Node* mergeKSortedLists(
struct Node* arr[], int K)
{
// Priority_queue 'pq' implemented
// as min heap with the help of
// 'compare' function
priority_queue<Node*, vector<Node*>, compare> pq;
// Push the head nodes of all
// the k lists in 'pq'
for (int i = 0; i < K; i++)
if (arr[i] != NULL)
pq.push(arr[i]);
// Handles the case when k = 0
// or lists have no elements in them
if (pq.empty())
return NULL;
struct Node *dummy = newNode(0);
struct Node *last = dummy;
// Loop till 'pq' is not empty
while (!pq.empty())
{
// Get the top element of 'pq'
struct Node* curr = pq.top();
pq.pop();
// Add the top element of 'pq'
// to the resultant merged list
last->next = curr;
last = last->next;
// Check if there is a node
// next to the 'top' node
// in the list of which 'top'
// node is a member
if (curr->next != NULL)
// Push the next node of top node
// in 'pq'
pq.push(curr->next);
}
// Address of head node of the required
// merged list
return dummy->next;
}
// Function to print the singly
// linked list
void printList(struct Node* head)
{
while (head != NULL)
{
cout << head->data << " ";
head = head->next;
}
}
// Driver code
int main()
{
// Number of linked lists
int N = 3;
// Number of elements in each list
int K = 4;
// An array of pointers storing the
// head nodes of the linked lists
Node* arr[N];
// Creating k = 3 sorted lists
arr[0] = newNode(1);
arr[0]->next = newNode(3);
arr[0]->next->next = newNode(5);
arr[0]->next->next->next = newNode(7);
arr[1] = newNode(2);
arr[1]->next = newNode(4);
arr[1]->next->next = newNode(6);
arr[1]->next->next->next = newNode(8);
arr[2] = newNode(0);
arr[2]->next = newNode(9);
arr[2]->next->next = newNode(10);
arr[2]->next->next->next = newNode(11);
// Merge the k sorted lists
struct Node* head = mergeKSortedLists(arr, N);
// Print the merged list
printList(head);
return 0;
}
Java
// Java code for the above approach
import java.io.*;
import java.util.*;
class Node {
int data;
Node next;
Node(int key)
{
data = key;
next = null;
}
}
// Class implements Comparator to compare Node data
class NodeComparator implements Comparator<Node> {
public int compare(Node k1, Node k2)
{
if (k1.data > k2.data)
return 1;
else if (k1.data < k2.data)
return -1;
return 0;
}
}
class GFG {
// Function to merge k sorted linked lists
static Node mergeKList(Node[] arr, int K)
{
// Priority_queue 'queue' implemented
// as min heap with the help of
// 'compare' function
PriorityQueue<Node> queue
= new PriorityQueue<>(new NodeComparator());
Node at[] = new Node[K];
Node head = new Node(0);
Node last = head;
// Push the head nodes of all
// the k lists in 'queue'
for (int i = 0; i < K; i++) {
if (arr[i] != null) {
queue.add(arr[i]);
}
}
// Handles the case when k = 0
// or lists have no elements in them
if (queue.isEmpty())
return null;
// Loop till 'queue' is not empty
while (!queue.isEmpty()) {
// Get the top element of 'queue'
Node curr = queue.poll();
// Add the top element of 'queue'
// to the resultant merged list
last.next = curr;
last = last.next;
// Check if there is a node
// next to the 'top' node
// in the list of which 'top'
// node is a member
if (curr.next != null) {
// Push the next node of top node
// in 'queue'
queue.add(curr.next);
}
}
// Address of head node of the required
// merged list
return head.next;
}
// Print linked list
public static void printList(Node node)
{
while (node != null) {
System.out.print(node.data + " ");
node = node.next;
}
}
public static void main(String[] args)
{
int N = 3;
// array to store head of linkedlist
Node[] a = new Node[N];
// Linkedlist1
Node head1 = new Node(1);
a[0] = head1;
head1.next = new Node(3);
head1.next.next = new Node(5);
head1.next.next.next = new Node(7);
// Limkedlist2
Node head2 = new Node(2);
a[1] = head2;
head2.next = new Node(4);
head2.next.next = new Node(6);
head2.next.next.next = new Node(8);
// Linkedlist3
Node head3 = new Node(0);
a[2] = head3;
head3.next = new Node(9);
head3.next.next = new Node(10);
head3.next.next.next = new Node(11);
Node res = mergeKList(a, N);
if (res != null)
printList(res);
System.out.println();
}
}
Python
# Python implementation to merge k sorted linked lists
# Using MIN HEAP method
import heapq
class Node:
def __init__(self, data):
self.data = data
self.next = None
def mergeKList(arr, K):
# Priority_queue 'queue' implemented
# as min heap with the help of
# 'compare' function
queue = []
for i in range(K):
if arr[i] != None:
heapq.heappush(queue, (arr[i].data, arr[i]))
dummy = Node(0)
last = dummy
while queue:
curr = heapq.heappop(queue)[1]
last.next = curr
last = last.next
if curr.next != None:
heapq.heappush(queue, (curr.next.data, curr.next))
return dummy.next
def printList(node):
while node != None:
print(node.data, end=" ")
node = node.next
print()
if __name__ == "__main__":
N = 3
a = [None] * N
# Linkedlist1
head1 = Node(1)
a[0] = head1
head1.next = Node(3)
head1.next.next = Node(5)
head1.next.next.next = Node(7)
# Limkedlist2
head2 = Node(2)
a[1] = head2
head2.next = Node(4)
head2.next.next = Node(6)
head2.next.next.next = Node(8)
# Linkedlist3
head3 = Node(0)
a[2] = head3
head3.next = Node(9)
head3.next.next = Node(10)
head3.next.next.next = Node(11)
res = mergeKList(a, N)
if res != None:
printList(res)
C#
using System;
using System.Collections.Generic;
class Node
{
public int data;
public Node next;
public Node(int key)
{
data = key;
next = null;
}
}
// Custom comparer to compare nodes based on data
class NodeComparer : IComparer<Node>
{
public int Compare(Node k1, Node k2)
{
if (k1.data > k2.data)
return 1;
else if (k1.data < k2.data)
return -1;
return 0;
}
}
class GFG
{
// Function to merge k sorted linked lists
static Node MergeKList(Node[] arr, int K)
{
// Priority queue implemented as a min-heap using custom comparer
PriorityQueue<Node> queue = new PriorityQueue<Node>(new NodeComparer());
Node head = new Node(0);
Node last = head;
// Enqueue the head nodes of all k lists in the queue
for (int i = 0; i < K; i++)
{
if (arr[i] != null)
{
queue.Enqueue(arr[i]);
}
}
// If the queue is empty, return null
if (queue.Count == 0)
return null;
// Loop until the queue is not empty
while (queue.Count > 0)
{
// Get the node with the smallest data from the queue
Node curr = queue.Dequeue();
// Add the node to the resultant merged list
last.next = curr;
last = last.next;
// Check if there is a node next to the current node in its list
if (curr.next != null)
{
// Enqueue the next node in the list
queue.Enqueue(curr.next);
}
}
// Return the head of the merged list
return head.next;
}
// Print linked list
public static void PrintList(Node node)
{
while (node != null)
{
Console.Write(node.data + " ");
node = node.next;
}
}
static void Main(string[] args)
{
int N = 3;
Node[] a = new Node[N];
// Linked list 1
Node head1 = new Node(1);
a[0] = head1;
head1.next = new Node(3);
head1.next.next = new Node(5);
head1.next.next.next = new Node(7);
// Linked list 2
Node head2 = new Node(2);
a[1] = head2;
head2.next = new Node(4);
head2.next.next = new Node(6);
head2.next.next.next = new Node(8);
// Linked list 3
Node head3 = new Node(0);
a[2] = head3;
head3.next = new Node(9);
head3.next.next = new Node(10);
head3.next.next.next = new Node(11);
Node res = MergeKList(a, N);
if (res != null)
PrintList(res);
Console.WriteLine();
}
}
// Priority queue implementation
class PriorityQueue<T>
{
private List<T> heap;
private IComparer<T> comparer;
public PriorityQueue(IComparer<T> comparer = null)
{
this.heap = new List<T>();
this.comparer = comparer ?? Comparer<T>.Default;
}
public int Count => heap.Count;
// Enqueue operation
public void Enqueue(T item)
{
heap.Add(item);
int i = heap.Count - 1;
while (i > 0)
{
int parent = (i - 1) / 2;
if (comparer.Compare(heap[parent], heap[i]) <= 0)
break;
Swap(parent, i);
i = parent;
}
}
// Dequeue operation
public T Dequeue()
{
if (heap.Count == 0)
throw new InvalidOperationException("Priority queue is empty.");
T result = heap[0];
int last = heap.Count - 1;
heap[0] = heap[last];
heap.RemoveAt(last);
last--;
int i = 0;
while (true)
{
int left = 2 * i + 1;
if (left > last)
break;
int right = left + 1;
int minChild = left;
if (right <= last && comparer.Compare(heap[right], heap[left]) < 0)
minChild = right;
if (comparer.Compare(heap[i], heap[minChild]) <= 0)
break;
Swap(i, minChild);
i = minChild;
}
return result;
}
// Swap two elements in the heap
private void Swap(int i, int j)
{
T temp = heap[i];
heap[i] = heap[j];
heap[j] = temp;
}
}
Javascript
class Node {
constructor(key) {
this.data = key;
this.next = null;
}
}
// Comparator function to compare Node data
function nodeComparator(k1, k2) {
if (k1.data < k2.data) return -1;
if (k1.data > k2.data) return 1;
return 0;
}
class PriorityQueue {
constructor(compare) {
this.heap = [];
this.compare = compare;
}
enqueue(value) {
this.heap.push(value);
this.bubbleUp();
}
bubbleUp() {
let index = this.heap.length - 1;
while (index > 0) {
let element = this.heap[index],
parentIndex = Math.floor((index - 1) / 2),
parent = this.heap[parentIndex];
if (this.compare(element, parent) < 0) break;
this.heap[index] = parent;
this.heap[parentIndex] = element;
index = parentIndex;
}
}
dequeue() {
let max = this.heap[0];
let end = this.heap.pop();
if (this.heap.length > 0) {
this.heap[0] = end;
this.sinkDown(0);
}
return max;
}
sinkDown(index) {
let left = 2 * index + 1,
right = 2 * index + 2,
largest = index;
if (
left < this.heap.length &&
this.compare(this.heap[left], this.heap[largest]) > 0
) {
largest = left;
}
if (
right < this.heap.length &&
this.compare(this.heap[right], this.heap[largest]) > 0
) {
largest = right;
}
if (largest !== index) {
[this.heap[largest], this.heap[index]] = [
this.heap[index],
this.heap[largest],
];
this.sinkDown(largest);
}
}
isEmpty() {
return this.heap.length === 0;
}
}
function mergeKLists(arr, K) {
const queue = new PriorityQueue(nodeComparator);
const at = new Array(K);
const head = new Node(0);
let last = head;
// Push the head nodes of all the k lists in 'queue'
for (let i = 0; i < K; i++) {
if (arr[i] !== null) {
queue.enqueue(arr[i]);
}
}
// Handles the case when k = 0
// or lists have no elements in them
if (queue.isEmpty()) return null;
// Loop till 'queue' is not empty
while (!queue.isEmpty()) {
// Get the top element of 'queue'
const curr = queue.dequeue();
// Add the top element of 'queue' to the resultant merged list
last.next = curr;
last = last.next;
// Check if there is a node next to the 'top' node
// in the list of which 'top' node is a member
if (curr.next !== null) {
// Push the next node of top node in 'queue'
queue.enqueue(curr.next);
}
}
// Address of head node of the required merged list
return head.next;
}
// Print linked list
function printList(node) {
let str = "";
while (node !== null) {
str += `${node.data} `;
node = node.next;
}
console.log(str);
}
// Testing
const N = 3;
// array to store head of linkedlist
const a = new Array(N);
// Linkedlist1
const head1 = new Node(1);
a[0] = head1;
head1.next = new Node(3);
head1.next.next = new Node(5);
head1.next.next.next = new Node(7);
// Limkedlist2
const head2 = new Node(2);
a[1] = head2;
head2.next = new Node(4);
head2.next.next = new Node(6);
head2.next.next.next = new Node(8);
// Linkedlist3
const head3 = new Node(0);
a[2] = head3;
head3.next = new Node(9);
head3.next.next = new Node(10);
head3.next.next.next = new Node(11);
const res = mergeKLists(a, N);
if (res !== null) printList(res);
console.log();
输出
0 1 2 3 4 5 6 7 8 9 10 11
时间复杂度:O(N * K * log K)
辅助空间:O(K)