이진 힙

class Heap {
  constructor() {
    this.items = [];
  }

  swap(index1, index2) {
    const temp = this.items[index1];
    this.items[index1] = this.items[index2];
    this.items[index2] = temp;
  }

  parentIndex(index) {
    return Math.floor((index - 1) / 2);
  }

  leftChildIndex(index) {
    return index * 2 + 1;
  }

  rigthChildIndex(index) {
    return index * 2 + 2;
  }

  parent(index) {
    return this.items[this.parentIndex(index)];
  }

  leftChild(index) {
    return this.items[this.leftChildIndex(index)];
  }

  rightChild(index) {
    return this.items[this.rigthChildIndex(index)];
  }

  peak() {
    return this.items[0];
  }

  size() {
    return this.items.length;
  }
}

최소 힙

class MinHeap extends Heap {
  bubbleDown() {
    let index = 0;
    while (this.leftChild(index)) {
      const smallerIndex =
        this.rightChild(index) && this.rightChild(index) < this.leftChild(index)
          ? this.rigthChildIndex(index)
          : this.leftChildIndex(index);
      if (this.items[index] < this.items[smallerIndex]) break;
      this.swap(smallerIndex, index);
      index = smallerIndex;
    }
  }

  bubbleUp() {
    let index = this.size() - 1;
    while (this.parent(index) && this.parent(index) > this.items[index]) {
      this.swap(this.parentIndex(index), index);
      index = this.parentIndex(index);
    }
  }

  add(item) {
    this.items.push(item);
    this.bubbleUp();
  }

  poll() {
    const item = this.peak();
    this.items[0] = this.items[this.size() - 1];
    this.items.pop();
    this.bubbleDown();
    return item;
  }
}

최대 힙

class MaxHeap extends Heap {
  bubbleDown() {
    let index = 0;
    while (this.leftChild(index)) {
      const biggerIndex =
        this.rightChild(index) && this.rightChild(index) > this.leftChild(index)
          ? this.rightChildIndex(index)
          : this.leftChildIndex(index);
      if (this.items[index] > this.items[biggerIndex]) break;
      this.swap(biggerIndex, index);
      index = biggerIndex;
    }
  }

  bubbleUp() {
    let index = this.size() - 1;
    while (this.parent(index) && this.parent(index) < this.items[index]) {
      this.swap(this.parentIndex(index), index);
      index = this.parentIndex(index);
    }
  }

  add(item) {
    this.items.push(item);
    this.bubbleUp();
  }

  poll() {
    const item = this.peak();
    this.items[0] = this.items[this.size() - 1];
    this.items.pop();
    this.bubbleDown();
    return item;
  }
}