#include <bits/stdc++.h> // Includes common standard libraries (vector, iostream, queue for priority_queue)
using namespace std; // Use the standard namespace
// Definition for a singly-linked list node.
int data; // Value stored in the node.
List* next; // Pointer to the next node in the list.
// Constructor to initialize a new node.
this->next = NULL; // New node initially points to NULL.
// Helper function to insert a new node at the end of a linked list.
// Used for building the input lists in main.
// 'head': Reference to the head pointer of the list.
// 'tail': Reference to the tail pointer of the list.
// 'val': The data value for the new node.
void insert(List* &head, List* &tail, int val) {
List* temp = new List(val); // Create a new node.
if(head == NULL) { // If the list is empty, new node is both head and tail.
} else { // If list is not empty, append to tail.
tail->next = temp; // Link current tail to new node.
tail = temp; // Update tail to the new node.
// Custom comparator class for the priority_queue.
// Defines the ordering logic for 'List*' pointers.
// For a MIN HEAP (priority_queue by default is max-heap), we want 'a' to have higher priority
// (i.e., come before 'b') if a->data < b->data.
// So, 'operator()' returns true if 'a' has *lower priority* than 'b' (meaning a's data is GREATER than b's data).
bool operator () (List* a, List* b) {
return a->data > b->data; // If true, 'a' is placed after 'b' in the conceptual ordering.
// Thus, smaller 'data' values will have higher priority (be at the top).
// Function to merge K sorted linked lists into a single sorted linked list.
// 'kLists': A vector where each element is the head pointer of a sorted linked list.
// Time Complexity: O(N log K), where N is the total number of nodes across all lists.
// Space Complexity: O(K) for the minHeap.
List* mergeSortedLists(vector<List* > kLists) {
// Step 1: Initialize a Min Heap.
// The heap will store 'List*' pointers, ordered by our custom 'compare' functor.
priority_queue<List*, vector<List*>, compare> minHeap;
int K = kLists.size(); // Number of input linked lists.
// Edge case: If there are no lists, return NULL.
// Populate the minHeap with the head nodes of all non-empty input lists.
// Each push operation takes O(log K) time. Total O(K log K) for this loop.
for(int i = 0; i < K; i++) {
if(kLists[i] != NULL) { // Only push if the list is not empty.
List* head = NULL; // Head of the new merged list.
List* tail = NULL; // Tail of the new merged list.
// Step 2: Extract elements from the heap and build the merged list.
// This loop runs N times (where N is the total number of nodes in all lists).
while(minHeap.size() > 0) {
// Get the node with the smallest data (at the top of the minHeap).
List* top = minHeap.top();
minHeap.pop(); // Remove it from the heap.
// If the extracted node has a next element in its original list, push it to the heap.
// This ensures we always have the next smallest candidate from that list.
minHeap.push(top->next); // Takes O(log K) time.
// Append the extracted 'top' node to our merged list.
if(head == NULL) { // If it's the very first node of the merged list.
head = tail = top; // It becomes both head and tail.
} else { // For subsequent nodes.
tail->next = top; // Link current tail to the extracted node.
tail = top; // Update tail to the newly added node.
// IMP: To ensure the last node of the merged list properly terminates,
// it's good practice to set tail->next = NULL; here, or after the loop.
// The current implementation relies on the original list's last node
// having next=NULL, which is usually true, but this explicit step is safer.
tail->next = NULL; // Ensure the last node points to NULL.
// Return the head of the newly formed merged sorted linked list.
vector<List*> kLists; // Vector to store the head pointers of K linked lists.
int K; // Number of linked lists.
cout << "Enter the value of K (number of lists) : ";
// Loop to input each of the K sorted linked lists.
for(int i = 0; i < K; i++) {
List* head = NULL; // Head of the current list being built.
List* tail = NULL; // Tail of the current list being built.
cout << "Enter the values for list " << i + 1 << " (-1 to stop) : ";
// Read values for the current list until -1 is entered.
if (val != -1) { // Ensure -1 itself is not added to the list.
insert(head, tail, val); // Use helper function to insert nodes.
cin >> val; // Read next value.
kLists.push_back(head); // Add the head of the newly built list to the vector.
// Call the function to merge the K sorted linked lists.
List* mergedHead = mergeSortedLists(kLists);
// Print the merged sorted linked list.
List* temp_ptr = mergedHead; // Use a temporary pointer to traverse and print.
cout << "Merged List : ";
while(temp_ptr != NULL) {
cout << temp_ptr->data << " ";
temp_ptr = temp_ptr->next;
// IMPORTANT: In C++, if nodes are dynamically allocated (using 'new'),
// they should ideally be 'delete'd to prevent memory leaks,
// especially for the merged list and any nodes that remained in 'kLists'
// but were not part of the final merged list (if any lists were empty initially).
// For competitive programming, this cleanup is often omitted for brevity.
Step-by-step Trace (Conceptual):
- Head of List 1: Node(1)
- Head of List 2: Node(2)
- Head of List 3: Node(4)
Heap (conceptually): { Node(1), Node(2), Node(4) } (Node with 1 at top)
- top = Node(1). Pop Node(1).
- Node(1)->next is Node(5). Push Node(5) to heap.
- Merged List: 1 -> NULL (head=tail=Node(1))
Heap: { Node(2), Node(4), Node(5) } (Node with 2 at top)
- top = Node(2). Pop Node(2).
- Node(2)->next is Node(3). Push Node(3) to heap.
- Merged List: 1 -> 2 -> NULL (tail=Node(2))
Heap: { Node(3), Node(4), Node(5) } (Node with 3 at top)
- top = Node(3). Pop Node(3).
- Node(3)->next is Node(8). Push Node(8) to heap.
- Merged List: 1 -> 2 -> 3 -> NULL (tail=Node(3))
Heap: { Node(4), Node(5), Node(8) } (Node with 4 at top)
- top = Node(4). Pop Node(4).
- Node(4)->next is Node(6). Push Node(6) to heap.
- Merged List: 1 -> 2 -> 3 -> 4 -> NULL (tail=Node(4))
Heap: { Node(5), Node(6), Node(8) } (Node with 5 at top)
- top = Node(5). Pop Node(5).
- Node(5)->next is Node(9). Push Node(9) to heap.
- Merged List: 1 -> 2 -> 3 -> 4 -> 5 -> NULL (tail=Node(5))
Heap: { Node(6), Node(8), Node(9) } (Node with 6 at top)
- top = Node(6). Pop Node(6).
- Node(6)->next is Node(7). Push Node(7) to heap.
- Merged List: 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> NULL (tail=Node(6))
Heap: { Node(7), Node(8), Node(9) } (Node with 7 at top)
- top = Node(7). Pop Node(7).
- Node(7)->next is NULL. Don't push.
- Merged List: 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> NULL (tail=Node(7))
Heap: { Node(8), Node(9) } (Node with 8 at top)
- top = Node(8). Pop Node(8).
- Node(8)->next is NULL. Don't push.
- Merged List: 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> NULL (tail=Node(8))
Heap: { Node(9) } (Node with 9 at top)
- top = Node(9). Pop Node(9).
- Node(9)->next is NULL. Don't push.
- Merged List: 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 9 -> NULL (tail=Node(9))
Output: Merged List : 1 2 3 4 5 6 7 8 9