【JavaScript数据结构】堆

42 阅读2分钟

堆是一种树状的数据结构,它满足堆的特性。最常见的堆有两种:最大堆(每个节点的值都大于或等于其孩子的值)和最小堆(每个节点的值都小于或等于其孩子的值)。

这里,我们将实现一个最小堆。使用数组来存储堆结构是最常见的方法,其中索引0是堆的顶部,其他元素按从左到右,从上到下的顺序排列。

class MinHeap {
  constructor() {
    this.heap = []; // 使用数组存储堆
  }

  // 获取父节点的索引
  getParentIndex(index) {
    return Math.floor((index - 1) / 2);
  }

  // 获取左孩子的索引
  getLeftChildIndex(index) {
    return 2 * index + 1;
  }

  // 获取右孩子的索引
  getRightChildIndex(index) {
    return 2 * index + 2;
  }

  // 交换两个节点的值
  swap(index1, index2) {
    [this.heap[index1], this.heap[index2]] = [this.heap[index2], this.heap[index1]];
  }

  // 向上调整节点,确保堆的特性不被破坏
  siftUp(index) {
    let parentIndex = this.getParentIndex(index);

    while (index > 0 && this.heap[parentIndex] > this.heap[index]) {
      this.swap(parentIndex, index);
      index = parentIndex;
      parentIndex = this.getParentIndex(index);
    }
  }

  // 向下调整节点,确保堆的特性不被破坏
  siftDown(index) {
    let leftChildIndex = this.getLeftChildIndex(index);
    let rightChildIndex = this.getRightChildIndex(index);
    let smallestIndex = index;

    if (leftChildIndex < this.heap.length && this.heap[leftChildIndex] < this.heap[smallestIndex]) {
      smallestIndex = leftChildIndex;
    }

    if (rightChildIndex < this.heap.length && this.heap[rightChildIndex] < this.heap[smallestIndex]) {
      smallestIndex = rightChildIndex;
    }

    if (smallestIndex !== index) {
      this.swap(smallestIndex, index);
      this.siftDown(smallestIndex);
    }
  }

  // 插入一个新元素
  insert(value) {
    this.heap.push(value);
    this.siftUp(this.heap.length - 1); // 调整堆
  }

  // 获取堆顶元素
  getTop() {
    return this.heap[0];
  }

  // 弹出堆顶元素
  popTop() {
    if (this.heap.length === 0) return null;
    let top = this.heap[0];
    this.heap[0] = this.heap[this.heap.length - 1];
    this.heap.pop();
    this.siftDown(0); // 调整堆
    return top;
  }

  // 返回堆的大小
  size() {
    return this.heap.length;
  }

  // 检查堆是否为空
  isEmpty() {
    return this.heap.length === 0;
  }
}

最大堆是一种特殊的树状数据结构,其中每个父节点的值都大于或等于其孩子节点的值。使用数组来表示堆是常见的,其中索引0表示堆顶,其他元素从左至右,从上至下排序。

class MaxHeap {
  constructor() {
    this.heap = []; // 使用数组存储堆
  }

  // 获取父节点的索引
  getParentIndex(index) {
    return Math.floor((index - 1) / 2);
  }

  // 获取左孩子的索引
  getLeftChildIndex(index) {
    return 2 * index + 1;
  }

  // 获取右孩子的索引
  getRightChildIndex(index) {
    return 2 * index + 2;
  }

  // 交换两个节点的值
  swap(index1, index2) {
    [this.heap[index1], this.heap[index2]] = [this.heap[index2], this.heap[index1]];
  }

  // 向上调整节点,确保堆的特性不被破坏
  siftUp(index) {
    let parentIndex = this.getParentIndex(index);

    while (index > 0 && this.heap[parentIndex] < this.heap[index]) {
      this.swap(parentIndex, index);
      index = parentIndex;
      parentIndex = this.getParentIndex(index);
    }
  }

  // 向下调整节点,确保堆的特性不被破坏
  siftDown(index) {
    let leftChildIndex = this.getLeftChildIndex(index);
    let rightChildIndex = this.getRightChildIndex(index);
    let largestIndex = index;

    if (leftChildIndex < this.heap.length && this.heap[leftChildIndex] > this.heap[largestIndex]) {
      largestIndex = leftChildIndex;
    }

    if (rightChildIndex < this.heap.length && this.heap[rightChildIndex] > this.heap[largestIndex]) {
      largestIndex = rightChildIndex;
    }

    if (largestIndex !== index) {
      this.swap(largestIndex, index);
      this.siftDown(largestIndex);
    }
  }

  // 插入一个新元素
  insert(value) {
    this.heap.push(value);
    this.siftUp(this.heap.length - 1); // 调整堆
  }

  // 获取堆顶元素
  getTop() {
    return this.heap[0];
  }

  // 弹出堆顶元素
  popTop() {
    if (this.heap.length === 0) return null;
    let top = this.heap[0];
    this.heap[0] = this.heap[this.heap.length - 1];
    this.heap.pop();
    this.siftDown(0); // 调整堆
    return top;
  }

  // 返回堆的大小
  size() {
    return this.heap.length;
  }

  // 检查堆是否为空
  isEmpty() {
    return this.heap.length === 0;
  }
}