Bird
Raised Fist0
DSA Typescriptprogramming

Why Heap Exists and What Sorted Array Cannot Do Efficiently in DSA Typescript - Why This Pattern

Choose your learning style10 modes available
Mental Model
A heap lets us quickly find and remove the smallest or largest item, which a sorted array can't do efficiently when we need to add or remove items often.
Analogy: Imagine a messy pile of papers where you want the most important one fast. A heap is like a special stack that always keeps the top paper the most important, so you grab it quickly. A sorted array is like a neat stack but adding or removing papers in the middle takes a lot of time.
Sorted array: [1, 3, 5, 7, 9]
Heap (min-heap):
      1
     / \
    3   5
   / \
  7   9
Dry Run Walkthrough
Input: Start with sorted array [1, 3, 5, 7, 9], then insert 2 and remove smallest element.
Goal: Show why inserting and removing smallest in a sorted array is slow, but fast in a heap.
Step 1: Insert 2 into sorted array by shifting elements to keep order
[1, 2, 3, 5, 7, 9]
Why: We must move elements to keep the array sorted, which takes time.
Step 2: Remove smallest element (1) by shifting all elements left
[2, 3, 5, 7, 9]
Why: Removing first element requires shifting all others, which is slow.
Step 3: Insert 2 into heap by adding at bottom and bubbling up
      1
     / \
    3   5
   / \  /
  7  9 2↑
Why: Heap inserts at bottom and moves up to keep heap order efficiently.
Step 4: Bubble up 2 to correct position in heap
      1
     / \
    2↑  5
   / \  /
  7  9 3
Why: We swap 2 with 3 to keep smallest on top without shifting whole structure.
Step 5: Remove smallest element (1) from heap by replacing root with last and bubbling down
      2↑
     / \
    3   5
   / \
  7   9
Why: Heap removes root and fixes order by bubbling down, avoiding full shifts.
Result:
Sorted array after insert and remove: [2, 3, 5, 7, 9]
Heap after insert and remove:
      2
     / \
    3   5
   / \
  7   9
Annotated Code
DSA Typescript
class MinHeap {
  heap: number[] = [];

  insert(val: number) {
    this.heap.push(val); // add at end
    this.bubbleUp(); // fix heap order
  }

  bubbleUp() {
    let idx = this.heap.length - 1;
    while (idx > 0) {
      let parentIdx = Math.floor((idx - 1) / 2);
      if (this.heap[parentIdx] <= this.heap[idx]) break;
      [this.heap[parentIdx], this.heap[idx]] = [this.heap[idx], this.heap[parentIdx]]; // swap
      idx = parentIdx; // move up
    }
  }

  removeMin() {
    if (this.heap.length === 0) return null;
    if (this.heap.length === 1) return this.heap.pop()!;
    const min = this.heap[0];
    this.heap[0] = this.heap.pop()!; // replace root with last
    this.bubbleDown(); // fix heap order
    return min;
  }

  bubbleDown() {
    let idx = 0;
    const length = this.heap.length;
    while (true) {
      let leftIdx = 2 * idx + 1;
      let rightIdx = 2 * idx + 2;
      let smallest = idx;

      if (leftIdx < length && this.heap[leftIdx] < this.heap[smallest]) {
        smallest = leftIdx;
      }
      if (rightIdx < length && this.heap[rightIdx] < this.heap[smallest]) {
        smallest = rightIdx;
      }
      if (smallest === idx) break;
      [this.heap[idx], this.heap[smallest]] = [this.heap[smallest], this.heap[idx]]; // swap
      idx = smallest; // move down
    }
  }

  print() {
    console.log(this.heap.join(' -> ') + ' -> null');
  }
}

// Sorted array insert and remove
let sortedArray = [1, 3, 5, 7, 9];
// Insert 2
let insertPos = sortedArray.findIndex(x => x > 2);
if (insertPos === -1) insertPos = sortedArray.length;
sortedArray.splice(insertPos, 0, 2);
// Remove smallest (first element)
sortedArray.shift();
console.log('Sorted Array:', sortedArray.join(' -> ') + ' -> null');

// Heap insert and remove
const heap = new MinHeap();
[1, 3, 5, 7, 9].forEach(x => heap.insert(x));
heap.insert(2);
heap.removeMin();
process.stdout.write('Heap: ');
heap.print();
this.heap.push(val); // add at end
insert new value at bottom of heap
this.bubbleUp(); // fix heap order
move inserted value up to maintain heap property
const min = this.heap[0];
store smallest value at root to return
this.heap[0] = this.heap.pop()!; // replace root with last
replace root with last element before bubbling down
this.bubbleDown(); // fix heap order
move root down to maintain heap property
let insertPos = sortedArray.findIndex(x => x > 2);
find position to insert 2 to keep array sorted
sortedArray.splice(insertPos, 0, 2);
insert 2 by shifting elements right
sortedArray.shift();
remove smallest element by shifting all left
OutputSuccess
Sorted Array: 2 -> 3 -> 5 -> 7 -> 9 -> null Heap: 2 -> 3 -> 5 -> 7 -> 9 -> null
Complexity Analysis
Time: O(n) for sorted array insert and remove because shifting elements takes time; O(log n) for heap insert and remove because bubbling up/down moves along tree height
Space: O(n) for both because they store all elements; heap uses array internally
vs Alternative: Heap is faster than sorted array for frequent insertions and removals because it avoids shifting many elements
Edge Cases
empty heap or array
removing smallest returns null or empty result without error
DSA Typescript
if (this.heap.length === 0) return null;
inserting smallest or largest value
heap bubbles up or array inserts at start or end correctly
DSA Typescript
let insertPos = sortedArray.findIndex(x => x > 2);
single element heap or array
removal returns that element and structure becomes empty
DSA Typescript
if (this.heap.length === 1) return this.heap.pop()!;
When to Use This Pattern
When you need to repeatedly get and remove the smallest or largest item quickly while also adding new items often, reach for the heap pattern because it keeps order efficiently without costly shifts.
Common Mistakes
Mistake: Trying to insert into a sorted array without shifting elements, causing order to break
Fix: Always find correct insert position and shift elements right to keep array sorted
Mistake: Not bubbling up or down in heap after insert or remove, breaking heap property
Fix: Always perform bubbleUp after insert and bubbleDown after remove to maintain heap order
Summary
A heap lets you quickly add items and get the smallest or largest without reordering everything.
Use a heap when you need fast access to min or max and frequent insertions or removals.
The key is that a heap keeps partial order with bubbling up/down, avoiding costly full shifts like in sorted arrays.

Practice

(1/5)
1. Why do we use a heap data structure instead of just a sorted array for priority operations?
easy
A. Because heaps use less memory than arrays
B. Because heaps store elements in sorted order permanently
C. Because heaps allow faster insertion and deletion of the highest priority element
D. Because heaps do not require any comparisons

Solution

  1. Step 1: Understand insertion and deletion in sorted arrays

    Inserting or deleting an element in a sorted array requires shifting elements, which takes O(n) time.
  2. Step 2: Compare with heap operations

    Heaps allow insertion and deletion of the highest priority element in O(log n) time by maintaining a partial order.
  3. Final Answer:

    Because heaps allow faster insertion and deletion of the highest priority element -> Option C
  4. Quick Check:

    Heap operations faster than sorted array for priority tasks [OK]
Hint: Heaps speed up insert/delete compared to sorted arrays [OK]
Common Mistakes:
  • Thinking heaps keep all elements fully sorted
  • Assuming heaps use less memory than arrays
  • Believing heaps avoid comparisons
2. Which of the following is the correct TypeScript syntax to insert an element into a min-heap represented as an array named heap?
easy
A. heap.insert(element); heapifyDown(heap);
B. heap.push(element); heapifyUp(heap);
C. heap.add(element); sort(heap);
D. heap.push(element); sort(heap);

Solution

  1. Step 1: Identify standard heap insertion steps

    Insertion usually involves adding the element at the end (push) and then moving it up (heapifyUp) to maintain heap property.
  2. Step 2: Check options for correct method names and order

    heap.push(element); heapifyUp(heap); uses push and heapifyUp, which is correct. Others use non-standard methods or sorting which is inefficient.
  3. Final Answer:

    heap.push(element); heapifyUp(heap); -> Option B
  4. Quick Check:

    Insert by push + heapifyUp [OK]
Hint: Insert by push then heapifyUp to fix heap [OK]
Common Mistakes:
  • Using sort() after insertion instead of heapify
  • Using non-existent methods like insert or add
  • Calling heapifyDown after insertion
3. Consider the following TypeScript code that uses a max-heap represented as an array. What will be the output after inserting 15?
let heap = [20, 10, 5];
function heapifyUp(heap: number[]) {
  let index = heap.length - 1;
  while (index > 0) {
    let parent = Math.floor((index - 1) / 2);
    if (heap[parent] >= heap[index]) break;
    [heap[parent], heap[index]] = [heap[index], heap[parent]];
    index = parent;
  }
}

heap.push(15);
heapifyUp(heap);
console.log(heap);
medium
A. [20, 15, 5, 10]
B. [20, 10, 15, 5]
C. [20, 15, 10, 5]
D. [15, 20, 10, 5]

Solution

  1. Step 1: Insert 15 at the end of heap array

    Heap becomes [20, 10, 5, 15].
  2. Step 2: Perform heapifyUp to maintain max-heap

    Compare 15 with parent 10 (index 1). Since 15 > 10, swap them. Heap becomes [20, 15, 5, 10]. Next, compare 15 with parent 20 (index 0). 15 < 20, stop.
  3. Final Answer:

    [20, 15, 5, 10] -> Option A
  4. Quick Check:

    Heap after insert and heapifyUp = [20, 15, 5, 10] [OK]
Hint: Insert at end, swap up while child > parent [OK]
Common Mistakes:
  • Not swapping 15 with 10
  • Swapping 15 with 20 incorrectly
  • Confusing heapifyUp with heapifyDown
4. The following TypeScript code attempts to remove the maximum element from a max-heap but has a bug. What is the error?
function removeMax(heap: number[]) {
  if (heap.length === 0) return null;
  const max = heap[0];
  heap[0] = heap.pop();
  heapifyDown(heap);
  return max;
}

function heapifyDown(heap: number[]) {
  let index = 0;
  const length = heap.length;
  while (true) {
    let left = 2 * index + 1;
    let right = 2 * index + 2;
    let largest = index;
    if (left < length && heap[left] > heap[largest]) largest = left;
    if (right < length && heap[right] > heap[largest]) largest = right;
    if (largest === index) break;
    [heap[index], heap[largest]] = [heap[largest], heap[index]];
    index = largest;
  }
}
medium
A. Does not properly handle the case when the heap has only one element
B. heapifyDown is called before updating heap[0]
C. The function does not return the removed max element
D. The heapifyDown function uses wrong child indices

Solution

  1. Step 1: Trace execution when heap.length === 1

    Assume heap = [10]. max = 10, heap.pop() returns 10 (heap = []), then heap[0] = 10 (heap = [10]), heapifyDown does nothing (no children). Heap remains [10], not emptied!
  2. Step 2: Logical bug confirmed

    Code runs without crash but fails to remove the single element. Requires special case: if (heap.length === 1) { return heap.pop(); } before general logic.
  3. Final Answer:

    Does not properly handle the case when the heap has only one element -> Option A
  4. Quick Check:

    Size=1 removal leaves heap non-empty [OK]
Hint: removeMax size=1 case not handled [OK]
Common Mistakes:
  • Not tracing single-element case where heap stays non-empty
  • Thinking heapifyDown is called too early
  • Believing return statement is missing
5. You have a large stream of numbers and want to always quickly find the smallest 3 numbers seen so far. Why is using a max-heap of size 3 better than keeping a sorted array of all numbers?
hard
A. Because sorted arrays do not allow any insertions
B. Because sorted arrays cannot store numbers in order
C. Because max-heaps use less memory than arrays regardless of size
D. Because max-heap of size 3 keeps only top 3 smallest with O(log 3) insertions, while sorted array grows and slows down

Solution

  1. Step 1: Understand problem constraints

    We want to track smallest 3 numbers from a large stream efficiently.
  2. Step 2: Compare max-heap of fixed size vs sorted array of all numbers

    Max-heap of size 3 keeps only 3 smallest numbers, insertion is O(log 3) = O(1). Sorted array grows with all numbers, insertion is O(n), slowing down over time.
  3. Final Answer:

    Because max-heap of size 3 keeps only top 3 smallest with O(log 3) insertions, while sorted array grows and slows down -> Option D
  4. Quick Check:

    Fixed-size heap beats growing sorted array for streaming top-k [OK]
Hint: Use fixed-size max-heap for top-k smallest in stream [OK]
Common Mistakes:
  • Thinking sorted arrays cannot store ordered data
  • Assuming max-heaps always use less memory
  • Believing sorted arrays disallow insertions
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard