siftDown(start, end) {
    let l = 2 * start + 1;
    let r = l + 1;
    let largest = start;

    if (l <= end && this.arr[l] > this.arr[largest]) {
      largest = l;
    }
    if (r <= end && this.arr[r] > this.arr[largest]) {
      largest = r;
    }
    if (largest !== start) {
      this.steps.push({action: "activate", idx: start});
      [this.arr[start], this.arr[largest]] = [this.arr[largest], this.arr[start]];
      this.steps.push({action: "compare", idx: largest});
      this.steps.push({action: "siftDown", from: start, to: largest});
      this.steps.push({action: "dim", parent: start, child: largest});
      this.siftDown(largest, end);
    }
  }
/**
   * Maintaining the max heap invariant by fixing a single voilation at the start
   * index, the process is then called recursively down the heap on every internal
   * node that voilates the invariant after their parent is fixed.
   * @param {number} start the initial root where the invariant is voilated
   * @param {number} end  the index that marks the end of the heap.
   */
Maintaining the max heap invariant by fixing a single voilation at the start
index, the process is then called recursively down the heap on every internal
node that voilates the invariant after their parent is fixed.
@param {number} start the initial root where the invariant is voilated
@param {number} end  the index that marks the end of the heap.
Maintaining the max heap invariant by fixing a single voilation at the start index the process is then called recursively down the heap on every internal node that voilates the invariant after their parent is fixed . @param { number } start the initial root where the invariant is voilated @param { number } end the index that marks the end of the heap .
siftDown(start, end) {
    let l = 2 * start + 1;
    let r = l + 1;
    let largest = start;
    if (l <= end && this.arr[l] > this.arr[largest]) {
      largest = l;
    }
    if (r <= end && this.arr[r] > this.arr[largest]) {
      largest = r;
    }
    if (largest !== start) {
      this.steps.push({action: "activate", idx: start});
      [this.arr[start], this.arr[largest]] = [this.arr[largest], this.arr[start]];
      this.steps.push({action: "compare", idx: largest});
      this.steps.push({action: "siftDown", from: start, to: largest});
      this.steps.push({action: "dim", parent: start, child: largest});
      this.siftDown(largest, end);
    }
  }
siftDown ( start , end ) { let l = 2 * start + 1 ; let r = l + 1 ; let largest = start ; if ( l <= end && this . arr [ l ] > this . arr [ largest ] ) { largest = l ; } if ( r <= end && this . arr [ r ] > this . arr [ largest ] ) { largest = r ; } if ( largest !== start ) { this . steps . push ( { action : "activate" , idx : start } ) ; [ this . arr [ start ] , this . arr [ largest ] ] = [ this . arr [ largest ] , this . arr [ start ] ] ; this . steps . push ( { action : "compare" , idx : largest } ) ; this . steps . push ( { action : "siftDown" , from : start , to : largest } ) ; this . steps . push ( { action : "dim" , parent : start , child : largest } ) ; this . siftDown ( largest , end ) ; } }
Maintaining the max heap invariant by fixing a single voilation at the start
 index, the process is then called recursively down the heap on every internal
 node that voilates the invariant after their parent is fixed.
Maintaining the max heap invariant by fixing a single voilation at the start index the process is then called recursively down the heap on every internal node that voilates the invariant after their parent is fixed .