Heaps (W7D5) - Learning Objectives

Heaps

  1. What is a max (or min) heap?
  2. How is a binary heap different from a binary search tree?
  3. What is a complete tree? How does it relate to heaps?
  4. What is a commmon way to represent heaps in JavaScript?
  5. In this representation, how can we find any particular node’s parent or children?
  6. What processes do we need to follow when we insert an element into a heap?
  7. What processes do we need to follow when we remove then root of a heap?
    deleteMax() {
      // Since our first element is `null` we take the element at index 1.
      // We want to keep null in the array if there are no other elements,
      // which is why we are returning null instead of popping for a length of 1.
      if (this.array.length === 2) return this.array.pop();
      if (this.array.length === 1) return null;
    
      // Since we're overwriting our index 1, we keep a reference to its value
      // so that we can return it later.
      let max = this.array[1];
      // We reassign the root of our heap to be the last element in our array.
      // Using .pop() removes that element from the end for us as well.
      this.array[1] = this.array.pop();
      // We check to see if the element that took our root's spot needs to be
      // sifted down into an appropriate position.
      this.siftDown(1);
      // After our sifting is done, our heap has been reorganize into a valid
      // configuration. We can now return the value that we originally removed.
      return max;
    }
    
    siftDown(idx) {
      let ary = this.array;
      let leftIdx = this.getLeftChild(idx);
      let rightIdx = this.getRightChild(idx);
      let leftVal = ary[leftIdx];
      let rightVal = ary[rightIdx];
    
      // If we do not have a child, leftVal or rightVal would be `undefined`.
      // We can't perform comparisons to `undefined` so we reassign them to be
      // -Infinity, which will always result in our value being greater, indicating
      // we are in a correct position (we can't sift down when we're already a leaf)
      if (leftVal === undefined) leftVal = -Infinity;
      if (rightVal === undefined) rightVal = -Infinity;
    
      // If we are greater than both of our children, we are in our final spot.
      if (ary[idx] > leftVal && ary[idx] > rightVal) return;
    
      // If one of our children is greater, we made it past the previous conditional.
      // We determine which child is greater, then assign that index as the the
      // one that we need to swap with.
      let swapIdx;
      if (leftVal < rightVal) {
        swapIdx = rightIdx;
      } else {
        swapIdx = leftIdx;
      }
    
      // We swap our current element with our largest child.
      [ ary[idx], ary[swapIdx] ] = [ ary[swapIdx], ary[idx] ];
      // We invoke siftDown again with the new index to see if we need to sift further.
      this.siftDown(swapIdx);
    }
  8. Given an array, determine if it represents a max (or min) heap.