0
0
DSA Javascriptprogramming

Merge K Sorted Lists Using Min Heap in DSA Javascript

Choose your learning style9 modes available
Mental Model
We combine many sorted lists into one sorted list by always picking the smallest current element from all lists using a min heap.
Analogy: Imagine you have K friends each reading a sorted book. You want to write down all the words in order. You ask each friend for their current word, pick the smallest word, write it down, then ask that friend for their next word. Repeat until all words are written.
Lists:
List1: 1 -> 4 -> 7 -> null
List2: 2 -> 5 -> 8 -> null
List3: 3 -> 6 -> 9 -> null

MinHeap (initial): [1, 2, 3]

Merged List: null
Dry Run Walkthrough
Input: lists: [1->4->7, 2->5->8, 3->6->9]
Goal: Merge all 3 sorted lists into one sorted list: 1->2->3->4->5->6->7->8->9
Step 1: Insert first nodes of all lists into min heap
MinHeap: [1, 2, 3]
Merged List: null
Why: We start by knowing the smallest elements from each list to pick the smallest overall
Step 2: Extract min (1) from heap and add to merged list; insert next node (4) from list1 into heap
MinHeap: [2, 3, 4]
Merged List: 1 -> null
Why: We add smallest element to merged list and bring next candidate from same list
Step 3: Extract min (2) from heap and add to merged list; insert next node (5) from list2 into heap
MinHeap: [3, 4, 5]
Merged List: 1 -> 2 -> null
Why: Continue picking smallest and replenishing heap from lists
Step 4: Extract min (3) from heap and add to merged list; insert next node (6) from list3 into heap
MinHeap: [4, 5, 6]
Merged List: 1 -> 2 -> 3 -> null
Why: Keep merging by always picking smallest current element
Step 5: Extract min (4) from heap and add to merged list; insert next node (7) from list1 into heap
MinHeap: [5, 6, 7]
Merged List: 1 -> 2 -> 3 -> 4 -> null
Why: Add next smallest and continue replenishing heap
Step 6: Extract min (5) from heap and add to merged list; insert next node (8) from list2 into heap
MinHeap: [6, 7, 8]
Merged List: 1 -> 2 -> 3 -> 4 -> 5 -> null
Why: Continue merging in sorted order
Step 7: Extract min (6) from heap and add to merged list; insert next node (9) from list3 into heap
MinHeap: [7, 8, 9]
Merged List: 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> null
Why: Keep picking smallest and adding next nodes
Step 8: Extract min (7) from heap and add to merged list; list1 has no more nodes
MinHeap: [8, 9]
Merged List: 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> null
Why: Add remaining elements from heap as lists finish
Step 9: Extract min (8) from heap and add to merged list; list2 has no more nodes
MinHeap: [9]
Merged List: 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> null
Why: Continue until all nodes are merged
Step 10: Extract min (9) from heap and add to merged list; list3 has no more nodes
MinHeap: []
Merged List: 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 9 -> null
Why: All nodes merged, heap empty
Result:
1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 9 -> null
Annotated Code
DSA Javascript
class ListNode {
  constructor(val = 0, next = null) {
    this.val = val;
    this.next = next;
  }
}

class MinHeap {
  constructor() {
    this.heap = [];
  }

  insert(node) {
    this.heap.push(node);
    this.bubbleUp();
  }

  bubbleUp() {
    let index = this.heap.length - 1;
    while (index > 0) {
      let parentIndex = Math.floor((index - 1) / 2);
      if (this.heap[parentIndex].val <= this.heap[index].val) break;
      [this.heap[parentIndex], this.heap[index]] = [this.heap[index], this.heap[parentIndex]];
      index = parentIndex;
    }
  }

  extractMin() {
    if (this.heap.length === 0) return null;
    if (this.heap.length === 1) return this.heap.pop();
    const min = this.heap[0];
    this.heap[0] = this.heap.pop();
    this.bubbleDown();
    return min;
  }

  bubbleDown() {
    let index = 0;
    const length = this.heap.length;
    while (true) {
      let left = 2 * index + 1;
      let right = 2 * index + 2;
      let smallest = index;

      if (left < length && this.heap[left].val < this.heap[smallest].val) {
        smallest = left;
      }
      if (right < length && this.heap[right].val < this.heap[smallest].val) {
        smallest = right;
      }
      if (smallest === index) break;
      [this.heap[index], this.heap[smallest]] = [this.heap[smallest], this.heap[index]];
      index = smallest;
    }
  }

  isEmpty() {
    return this.heap.length === 0;
  }
}

function mergeKLists(lists) {
  const minHeap = new MinHeap();

  // Insert first node of each list into min heap
  for (const node of lists) {
    if (node !== null) {
      minHeap.insert(node);
    }
  }

  const dummy = new ListNode(0);
  let current = dummy;

  // Extract min and add next nodes until heap is empty
  while (!minHeap.isEmpty()) {
    const minNode = minHeap.extractMin();
    current.next = minNode;
    current = current.next;
    if (minNode.next !== null) {
      minHeap.insert(minNode.next);
    }
  }

  return dummy.next;
}

// Driver code using dry_run input
const list1 = new ListNode(1, new ListNode(4, new ListNode(7)));
const list2 = new ListNode(2, new ListNode(5, new ListNode(8)));
const list3 = new ListNode(3, new ListNode(6, new ListNode(9)));

const mergedHead = mergeKLists([list1, list2, list3]);

// Print merged list
let output = '';
let curr = mergedHead;
while (curr !== null) {
  output += curr.val + ' -> ';
  curr = curr.next;
}
output += 'null';
console.log(output);
for (const node of lists) { if (node !== null) { minHeap.insert(node); } }
Insert first nodes of all lists into min heap to start merging
while (!minHeap.isEmpty()) { const minNode = minHeap.extractMin(); current.next = minNode; current = current.next; if (minNode.next !== null) { minHeap.insert(minNode.next); } }
Repeatedly extract smallest node, add to merged list, and insert next node from same list
OutputSuccess
1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 9 -> null
Complexity Analysis
Time: O(N log K) because we process all N nodes and each heap operation takes O(log K) where K is number of lists
Space: O(K) for the heap storing one node from each list at a time
vs Alternative: Naive merging by repeatedly merging two lists at a time takes more time (O(KN)) compared to min heap approach which is more efficient
Edge Cases
Empty input lists array
Returns null as there are no nodes to merge
DSA Javascript
if (node !== null) { minHeap.insert(node); }
Some lists are empty (null)
Only non-empty lists contribute nodes; empty lists ignored
DSA Javascript
if (node !== null) { minHeap.insert(node); }
All lists empty
Returns null as no nodes exist
DSA Javascript
if (node !== null) { minHeap.insert(node); }
When to Use This Pattern
When you need to merge multiple sorted lists efficiently, use a min heap to always pick the smallest current element from all lists.
Common Mistakes
Mistake: Not inserting the next node of the extracted node back into the heap
Fix: After extracting minNode, check if minNode.next exists and insert it into the heap
Mistake: Using a max heap or sorting all nodes at once instead of incremental merging
Fix: Use a min heap to always pick the smallest node incrementally for efficiency
Summary
Merges K sorted linked lists into one sorted linked list using a min heap.
Use when you have multiple sorted lists and want to merge them efficiently.
The key is to always pick the smallest current node from all lists using a min heap.