📌  相关文章
📜  使用最小堆合并 K 个已排序链表的 Javascript 程序 – 第 2 组(1)

📅  最后修改于: 2023-12-03 14:49:55.428000             🧑  作者: Mango

使用最小堆合并 K 个已排序链表的 JavaScript 程序 – 第 2 组

在处理大量数据时,使用最小堆是一种常见且有效的方法。本文将介绍如何使用最小堆来合并 K 个已排序链表。这个问题可以使用多种方法来解决,但是在本文中,我们将专注于使用最小堆来完成此任务。

问题描述

给定 K 个已排序链表,将它们合并成一个排序链表。例如,当 K = 3 时,给定的链表集合为:

[
  1 -> 4 -> 5,
  1 -> 3 -> 4,
  2 -> 6
]

合并后的链表为 1 -> 1 -> 2 -> 3 -> 4 -> 4 -> 5 -> 6。

解决方案

使用最小堆可以使得合并 K 个已排序链表变得非常高效。它的基本思路是首先将每个链表的第一个节点插入到最小堆中。然后,从堆中取出最小元素,将它的下一个节点插入到堆中。重复此过程,直到所有节点都被插入到新链表中。

下面是使用最小堆的 JavaScript 代码。它使用了一个自定义的 ListNode 类来表示链表节点。函数 mergeKLists 接收一个链表数组,返回合并后的链表头节点。

class ListNode {
  constructor(val, next = null) {
    this.val = val;
    this.next = next;
  }
}

const mergeKLists = lists => {
  const heap = new MinHeap();
  const dummy = new ListNode(0);
  let tail = dummy;

  // Insert the first node of each list into the heap
  for (const list of lists) {
    if (list) heap.insert(list);
  }

  // Take the smallest node from the heap and insert its next node
  while (!heap.isEmpty()) {
    const node = heap.pop();
    tail.next = node;
    tail = tail.next;
    if (node.next) heap.insert(node.next);
  }

  return dummy.next;
};

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

  insert(val) {
    this.heap.push(val);
    this.bubbleUp(this.heap.length - 1);
  }

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

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

  bubbleUp(idx) {
    if (idx === 0) return;
    const pIdx = Math.floor((idx - 1) / 2);
    if (this.heap[idx].val < this.heap[pIdx].val) {
      [this.heap[idx], this.heap[pIdx]] = [this.heap[pIdx], this.heap[idx]];
      this.bubbleUp(pIdx);
    }
  }

  bubbleDown(idx) {
    const [leftIdx, rightIdx] = [idx * 2 + 1, idx * 2 + 2];
    const leftVal = this.heap[leftIdx]?.val;
    const rightVal = this.heap[rightIdx]?.val;
    const currentVal = this.heap[idx].val;

    // If the current node is already smaller than its children, stop bubbling down
    if (currentVal <= leftVal && currentVal <= rightVal) return;

    // Otherwise, swap the current node with its smallest child
    const swapIdx = leftVal < rightVal ? leftIdx : rightIdx;
    [this.heap[idx], this.heap[swapIdx]] = [this.heap[swapIdx], this.heap[idx]];
    this.bubbleDown(swapIdx);
  }
}
总结

在本文中,我们介绍了如何使用最小堆来合并 K 个已排序链表。这个算法的时间复杂度为 O(N log K),其中 N 是所有链表中节点的总数。对于大型数据集,使用最小堆将大大提高算法的效率。