CMD Guide
HomeDSAHeap

Introduction to Heap

A heap works by enforcing one weak invariant — every parent dominates its children (≥ for max-heap, ≤ for min-heap) — on top of a shape invariant (complete binary tree), which together let it live in a plain array with no pointers and guarantee the extreme element is always at index 0, while insert/remove only need to fix a single root-to-leaf path rather than re-sort anything.

Recognize the pattern

Brute force → optimal

Brute force A (unsorted array): insert is O(1) append, but find-min/max scans everything: O(n) per query.

Brute force B (fully sorted array): find-min is O(1), but insert costs O(n) to shift elements into place. You've just moved the cost, not removed it.

Optimal (heap): accept a weaker order — only parent–child, never sibling–sibling. This buys O(1) peek and O(log n) insert/remove, because restoring the invariant only ever touches one root-to-leaf path, never the whole array.

Array representation

A heap is stored via level-order (BFS) traversal in an array — no pointers needed. For a node at index i: left child is at 2i+1, right child at 2i+2, parent at (i-1)/2 (integer division). Because the tree is always complete, these formulas always land on a valid, contiguous slot — that's the whole trick that makes arrays work here.

Complexity from first principles

Height: a complete binary tree with n nodes has height h = ⌊log₂ n⌋, because each level doubles the node count and the array packs levels contiguously with no gaps.

Insert (sift-up): the new element starts at a leaf and, in the worst case, swaps once per level on the way to the root. Number of comparisons/swaps ≤ h = O(log n). Peek: O(1) — it's just array[0].

Extract-min/max (sift-down): move the last element to the root (O(1)), then at each of h levels compare with (up to) 2 children and swap with the larger/smaller one: O(1) work × h levels = O(log n).

Build-heap from n elements: naive "insert n times" gives O(n log n). But bottom-up heapify (sift-down starting from the last internal node) is O(n): most nodes are near the bottom where sift-down does almost no work; summing cost×count over levels gives ∑ n/2^(h+1) · h = O(n), not O(n log n).

Space: O(n) for the array, O(1) extra for insert/extract (in-place swaps), O(log n) if sift-down/up is written recursively (call stack) — use the iterative form to keep it O(1).

Worked example: inserting 5 into a max-heap

Heap array: [16,14,10,8,7,9,3]. Insert 5 at the end, then sift up.

StepArray stateAction
1[16,14,10,8,7,9,3,5]Append 5 at index 7 (last position)
2parent(7)=(7-1)/2=3 → value 88 ≥ 5, heap property holds → stop

Now extract-max on [16,14,10,8,7,9,3]:

StepArray stateAction
1[3,14,10,8,7,9]Save 16 as result; move last element (3) to root; shrink array
2[14,3,10,8,7,9]children of 3 (idx0) are 14,10 → swap with larger child 14
3[14,8,10,3,7,9]3 now at idx1; children 8,7 → swap with larger child 8
4final3 at idx3 is a leaf → stop. Result: 16 removed, heap restored
public class MinHeap {
    private int[] a;
    private int size;

    public MinHeap(int capacity) { a = new int[capacity]; size = 0; }

    public int peek() {
        if (size == 0) throw new java.util.NoSuchElementException("heap is empty");
        return a[0];
    }

    public void insert(int val) {
        a[size] = val;
        int i = size++;
        while (i > 0) {
            int parent = (i - 1) / 2;
            if (a[parent] <= a[i]) break;
            swap(parent, i);
            i = parent;
        }
    }

    public int extractMin() {
        if (size == 0) throw new java.util.NoSuchElementException("heap is empty");
        int min = a[0];
        a[0] = a[--size];
        siftDown(0);
        return min;
    }

    private void siftDown(int i) {
        while (true) {
            int left = 2 * i + 1, right = 2 * i + 2, smallest = i;
            if (left < size && a[left] < a[smallest]) smallest = left;
            if (right < size && a[right] < a[smallest]) smallest = right;
            if (smallest == i) break;
            swap(i, smallest);
            i = smallest;
        }
    }

    private void swap(int x, int y) { int t = a[x]; a[x] = a[y]; a[y] = t; }
}

Pitfalls

When to use / when NOT — trade-offs

StructurePeekInsertExtract-topSorted iteration
HeapO(1)O(log n)O(log n)No (O(n log n) to drain)
Sorted arrayO(1)O(n)O(1) (from end)Yes, free
Balanced BST / TreeMapO(log n)O(log n)O(log n)Yes, in-order

Use a heap when you need fast repeated access to only the current extreme value and don't care about full ordering (priority queues, top-k, Dijkstra) — and note that two heaps back-to-back solve running median: a max-heap of the lower half plus a min-heap of the upper half gives O(log n) insert and O(1) median. Prefer a sorted structure or balanced BST when you need range queries, predecessor/successor lookups, or full sorted traversal — a heap can't do those efficiently since it only orders parent–child, not siblings.

Takeaways

Recall: Why is bottom-up heapify O(n) instead of O(n log n) even though each sift-down is O(log n) in the worst case?

🎯 Drill Ladder — survive the follow-ups

L0 · A heap is a complete binary tree that maintains the parent dominance invariant to support O(1) peek and O(log n) extract-min/max.

L1 · ⑤ Adversary/Edge — “If you insert N elements one-by-one into an empty binary heap, what is the overall time complexity?”
Trap: It is O(N) because heap construction is linear.
Bar: Bottom-up heapify (building from an array of size N) is O(N), but inserting N elements one-by-one takes O(N log N) time because each insertion can walk up the height of the heap. Heap Operations

L2 · ② Failure — “You are implementing a binary heap in an array. What happens if you run index arithmetic (like parent = (i-1)/2) on a 0-indexed array?”
Trap: It works perfectly for all indices.
Bar: Calculating parent for i = 0 yields i = 0 (or -1 in languages with negative division), causing infinite loops; add an explicit boundary check if (i == 0) return; to prevent index calculation bugs. Heap Operations

L3 · ③ Scale — “You are running Dijkstra's algorithm on a graph with V = 10⁵ and E = 10⁶. The heap size grows with every relaxed edge. How do you prevent memory exhaustion?”
Trap: Unconditionally insert every relaxed edge into the heap.
Bar: This allows the heap to grow to size O(E); maintain a mapping of node -> heap_index and use the decreaseKey operation to update node distances in place, keeping heap size bounded by O(V). Heap Operations

L4 · ① Concurrency — “How do you implement a concurrent Priority Queue using a binary heap without bottlenecking threads on a single lock?”
Trap: Synchronize the insert and extract-min methods.
Bar: A single lock serializes all operations; use skip lists or randomized heap structures that allow lock-free atomic pointer operations to avoid full heap serialization. Introduction to Heap

L5 · ⑥ Cost/Simplicity — “If we want to find the top-K elements in a stream of N numbers, why use a min-heap of size K instead of sorting the stream?”
Trap: Sorting the stream is too slow.
Bar: Sorting the entire stream takes O(N log N) time and O(N) space; a min-heap of size K processes the stream in O(N log K) time and O(K) space, which is highly efficient when K << N. Introduction to Heap

The floor keeps dropping: How do you implement a d-ary heap (where each node has d children) and what is the optimal choice of d for Dijkstra's algorithm?

Self-locate: died at L1 → you present mid-level; L4+ → staff signal.

Facing any new concept? Hit it with the six: concurrent? failing? at 100×? over time? adversarial? worth the cost? — that's the interviewer's whole playbook.


Synthesized from CLRS (Cormen et al., Introduction to Algorithms), Sedgewick & Wayne's Algorithms, and standard heap/priority-queue treatments used in interview-prep references.

🤖 Don't fully get this? Learn it with Claude

Stuck on Introduction to Heap? Open Claude, copy a block below, and it'll teach you this exact concept — visually and interactively.

🎨 Explain it visually

Build the mental picture, not memorization.

I just read a lesson on **Introduction to Heap** (DSA) and want to truly understand it. Explain Introduction to Heap from first principles using ONE vivid real-world analogy and a visual mental model — draw it as ASCII art or a clear step-by-step diagram — with a concrete example using real numbers. Then ask me one question to check I got the mental picture, and wait for my reply. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
🤔 Walk me through it (interactive)

Socratic — adapts to where you're stuck.

Teach me **Introduction to Heap** interactively. Ask me ONE guiding question at a time, wait for my answer, and adapt to my confusion — build the idea with me step by step instead of explaining it all at once. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
🧪 Quiz me & fix my gaps

Active recall exposes what you missed.

Quiz me on **Introduction to Heap** with 5 questions, easy to tricky, ONE at a time. Tell me if each answer is right; at the end, explain clearly what I got wrong and why. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
🧠 Make it stick

Intuition + hook + flashcards for long-term memory.

Help me remember **Introduction to Heap** for the long term: give the one-sentence intuition, a memorable hook/mnemonic, a tiny worked example, and 3 active-recall flashcards (Q -> A). If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.

📝 My notes