skip to content

Heaps & Priority Queues

Understand the heap as its own interview subject: how the structure works under the hood, how priority queue APIs expose it, and which classic problem shapes it unlocks. Interviewers lean on heaps because one simple invariant connects directly to complexity arguments, library fluency, and pattern recognition.

part ofData structures & algorithmsoverview, primer and where to startread it →
on this pageshow

questions

page 1 of 2

Why is extract-min from a min-heap O(log n) when the minimum already sits at the root?

level: juniorimportance: must knowfreq 78%

answer

  1. separate reading the top from removing it
  2. what fills the hole at the root?
  3. the shape must stay a complete tree
  4. the moved key travels down level by level
  5. height of a complete tree over n nodes

basics

~20 s

Finding the minimum is O(1) — it sits at the root. Removing it costs O(log n): the last element is moved into the empty root slot and sifted down through the tree's height until the heap property holds again.

solid answer

~50 s

Two different operations get conflated here. Peeking — reading the minimum — really is O(1), because the heap invariant guarantees the smallest key is at the root and you never search for it. Extracting is peek plus repair. Removing the root leaves a hole, and the only element you can delete without breaking the complete-tree shape is the very last one, so that element is moved into the root. It is almost certainly not the smallest key, so it sifts down: at each level you compare it with its children, swap it with the smaller child, and continue until it is smaller than both children or reaches a leaf. A complete binary tree over `n` nodes has height about `log2(n)`, and that height bounds the number of levels the sift can traverse — hence O(log n) for extract and O(1) for peek.

go deeper

for a junior

Be ready to state both numbers without hesitating: peek O(1), extract O(log n), and say in one sentence why they differ — the answer is already positioned, but deleting it breaks the invariant that positioned it.

for a middle

Explain the two-move deletion out loud: return the root, move the last element up, sift it down. Tie the log n directly to the height of a complete binary tree rather than quoting it as a memorised fact.

for a senior

Show you know what the invariant does and does not buy: one extreme element cheaply, no ordering anywhere else. Be able to say why a rebuild-after-every-removal implementation is a real production defect and what it costs.

for a principal

Frame it as a deliberate purchase: a heap buys the single extreme key at O(log n) maintenance and refuses to pay for full ordering. Be able to argue when that is the right trade for a workload and when it is not.

## The claim being tested "The minimum is at the root, so extract-min is O(1)" is one of the most common wrong answers about heaps, and it is wrong for an instructive reason: it confuses **locating** the answer with **restoring the structure that made it easy to locate**. A min-heap is a complete binary tree in which every node's key is less than or equal to both of its children's keys. That single invariant is what puts the smallest key at the root. It is a *local* rule — parent versus child — that happens to have a *global* consequence. And local rules have to be repaired locally after every change. ## A concrete board Picture an emergency-room triage board where each record carries a priority score (lower means more urgent) and the board is kept as a min-heap so the next patient to be seen is always on top: ``` scores: [2, 3, 20, 9, 4, 30, 25] 2 / \ 3 20 / \ / \ 9 4 30 25 ``` **Peek** answers "who is next?" — read the root, score 2, done. No comparisons, no traversal. O(1), and it does *not* remove anything: peek and extract are separate operations, and a candidate who says "looking at the top removes it" has confused a heap with a consuming read. **Extract-min** answers "take the next patient off the board." Now the work starts. ## Why the last element climbs to the root Removing the root leaves a hole at the top. The heap's shape rule says the tree must stay *complete*: every level full except possibly the last, which fills left to right. In the flat-array layout that shape rule is what lets the structure live in a contiguous block with no gaps. The only element whose removal preserves completeness is the **last** one. So extraction is done in two moves: return the root's value, then move the last element into the root slot and shrink the size by one. On the board above, removing score 2 moves score 25 to the top: ``` 25 / \ 3 20 / \ / 9 4 30 ``` The shape is legal again, but the *ordering* is badly wrong: 25 sits above 3. ## Sift-down: the O(log n) part Sift-down (also called bubble-down or heapify-down) walks the misplaced key toward the leaves. At each step it looks at the node's children, picks the **smaller** one, and if that child is smaller than the node, swaps them and continues from the child's position. It stops as soon as the node is smaller than or equal to both children, or when it runs out of children. On the board: 25 versus children {3, 20} → swap with 3. Then 25 versus children {9, 4} → swap with 4. Then 25 has no children left. Two levels of work, and the board is a valid min-heap again with score 3 on top. The cost is bounded by how many levels there are. A complete binary tree with `n` nodes has height `floor(log2(n))`, because each level roughly doubles the node count: 1, 2, 4, 8, … So a sift-down does at most about `log2(n)` swap steps, each doing a constant amount of comparison work. That is the whole derivation of the famous O(log n): **it is the tree's height, nothing more**. Double the number of patients on the board and extraction gets one extra step, not twice as much work. ## Two consequences worth knowing **The second-smallest is not at index 1.** It is guaranteed only to be one of the root's two children — the invariant says nothing about which side. Finding it takes one comparison, not zero, and the mistake reveals someone who is picturing a sorted array rather than a partially ordered tree. **A heap is not sorted.** The array `[2, 3, 20, 9, 4, 30, 25]` is a perfectly valid heap and is nowhere near sorted order. The invariant buys you the *one* extreme element cheaply, and deliberately buys nothing else — which is precisely why building and maintaining it is cheaper than keeping a fully ordered structure. If someone tells you they rebuild the whole structure after each removal, they have thrown that advantage away and turned an O(log n) operation into a linear one. ## The summary to say out loud Peek is O(1) because the invariant already positioned the answer. Extract is O(log n) because deleting the root breaks the invariant, and repairing it costs one pass down the height of a complete tree.

  • What does it cost to look at the highest-priority record without removing it?
    O(1). The heap invariant guarantees the extreme key is at the root, so peek is a single read with no comparisons and no traversal. Peek and extract are distinct operations — peek leaves the structure untouched, which is why a scheduler can poll the front of the board cheaply and only pay the O(log n) repair when it actually commits to removing the record.
  • Why move the last element into the root instead of promoting the smaller child upward?
    Promoting children upward also restores the ordering, but the hole then ends up at some arbitrary leaf rather than at the last slot — which punches a gap into the contiguous layout and breaks the complete-tree shape. Moving the last element keeps the block gap-free, and it costs the same asymptotically: one pass down the height either way.
  • Can an extract-min ever finish in fewer than log n steps?
    Yes. Sift-down stops the moment the sinking key is smaller than or equal to both of its children, so a lucky key can settle after one level. Do not count on it, though: the key that gets moved to the root came from the bottom of the tree, so it is usually a large one and usually travels most of the height. O(log n) is a tight expectation here, not just an upper bound.

Reading the name at the top of the triage board is instant. Taking that patient off the board is what forces you to reshuffle the queue underneath so the next-most-urgent name rises to the top.

saying these in an interview costs you the question

  • Claiming extract is O(1) because the minimum is at the root
  • Saying peek removes the element it returns
  • Believing the second-smallest key is always the root's left child
  • Rebuilding the whole structure after every removal
  • Assuming the tree may be left with a gap in the middle

context

open as a page

Why is bottom-up heapify cheaper than inserting n items one at a time into a heap?

level: juniorimportance: must knowfreq 72%

basics

~20 s

Bottom-up heapify turns an array of n items into a heap in O(n) time, while n successive inserts cost O(n log n) in the worst case. Same heap, lower cost, whenever every item is available up front.

open as a page

In a min-heap held in an array, is that array sorted, and what does the heap property actually guarantee?

level: juniorimportance: must knowfreq 82%

basics

~20 s

A min-heap's array is not sorted. The property constrains only parent versus child, so every root-to-leaf path is non-decreasing while siblings may sit in any order. Only index 0 is guaranteed: it holds the minimum.

open as a page

What operations define the priority queue abstraction, and how does it differ from a FIFO queue?

level: juniorimportance: must knowfreq 80%

basics

~20 s

A priority queue supports three operations: insert an item with a priority, peek at the top-priority item, and extract that item. A FIFO queue hands back items in arrival order; a priority queue hands back the most urgent one first.

open as a page

A standard-library priority queue only pops the smallest key, but your scheduler must serve the highest priority first. What are your options?

level: juniorimportance: must knowfreq 74%

basics

~10 s

Give the queue a reversed comparison function, or push negated numeric keys. The reversed comparison is safer and self-documenting; negation works only for numeric keys and forces every read site to remember the flip.

open as a page

How does a min-heap merge k sorted input streams into one ordered output stream?

level: juniorimportance: must knowfreq 74%

basics

~20 s

Keep only the current head of each of the k streams in a min-heap. Repeatedly extract the smallest, emit it, and push that same stream's next element in its place. The heap never grows beyond k entries.

open as a page

Why must a size-k heap that keeps the k largest values be a min-heap rather than a max-heap?

level: juniorimportance: must knowfreq 78%

basics

~20 s

The heap must be a min-heap because its root is the smallest of the k values you are still keeping — the bar a new value must beat. A max-heap would evict the largest values and leave you the k smallest.

open as a page

Why does a running median over a live stream use two heaps rather than one sorted buffer?

level: juniorimportance: must knowfreq 78%

basics

~20 s

A max-heap holds the lower half of the samples and a min-heap the upper half, so the median sits at the heap tops: O(1) to read, O(log n) to absorb a new sample. A sorted buffer costs O(n) per insert to shift elements.

open as a page

Finding the 100 cheapest of 10 million products: sort, size-k heap, or quickselect?

level: juniorimportance: must knowfreq 80%

basics

~20 s

Sorting the whole catalog costs O(n log n) to answer a question about 100 items. A retained-candidate heap does one pass in O(n log k) with O(k) memory; quickselect averages O(n) but rearranges the input and needs it all resident.

open as a page

In a min-heap sift-down, why must you swap the node with its smaller child, not its left child?

level: middleimportance: must knowfreq 62%

basics

~20 s

The promoted child becomes the parent of both children, so it must be the smaller one. Promote the left child while the right is smaller and the new parent exceeds its sibling — the property breaks below the swap, where nothing rechecks it.

open as a page

Why is Floyd's bottom-up heap build O(n) when a single sift-down costs up to O(log n)?

level: middleimportance: must knowfreq 66%

basics

~20 s

Sift-down cost tracks a node's height above the leaves, not the tree's height. Half the nodes are leaves and never move, a quarter move at most one level; the heights summed over all nodes total about n.

open as a page

In a 0-indexed array heap, why are a node's children at 2i+1 and 2i+2 and its parent at (i-1)/2?

level: middleimportance: must knowfreq 74%

basics

~20 s

Level-order layout forces the arithmetic. Level L starts at index 2^L - 1, and the k-th node of a level parents nodes 2k and 2k+1 of the next; substituting collapses to children 2i+1, 2i+2 and parent floor((i-1)/2).

open as a page

Why do most priority queues use a binary heap rather than a sorted list or a balanced search tree?

level: middleimportance: must knowfreq 72%

basics

~20 s

A binary heap does exactly what the priority queue contract asks and no more: it keeps only a partial order, so insert and extract cost O(log n) and peek O(1). Sorted lists pay O(n) per insert; search trees pay pointer and cache overhead for ordering nobody asked for.

open as a page

A standard-library priority queue has no decrease-key — how do you change a queued item's priority?

level: middleimportance: must knowfreq 62%

basics

~20 s

Standard-library priority queues expose no decrease-key. Push a fresh entry at the new priority and discard outdated entries when they surface at the top. Mutating a stored key in place does not re-sift the heap and silently corrupts its order.

open as a page

Why is heap-based k-way merge O(N log k) but merging the k sources pairwise in a loop O(N*k)?

level: middleimportance: must knowfreq 66%

basics

~20 s

The heap touches each element twice, at log k cost each. Merging source after source into one growing accumulator re-copies everything already accumulated on every round, so the earliest elements are copied about k times.

open as a page

With n = 100 million readings and k = 100, what does a size-k heap actually save over sorting?

level: middleimportance: must knowfreq 72%

basics

~20 s

Roughly a fourfold smaller log factor: log2(100) is about 6.6 against about 26.6 for 100 million. The real saving is elsewhere — 100 resident values instead of 100 million, in a single forward pass over data of unknown length.

open as a page

In a two-heap running median, what invariant holds after every insert, and how is it restored?

level: middleimportance: must knowfreq 62%

basics

~20 s

Every value in the max-heap is at most every value in the min-heap, and the two sizes differ by at most one. A single pop-and-push, moving one top from the heavier heap to the lighter one, restores the size part after any insert.

open as a page

Quickselect runs in expected O(n) — why isn't it the default way to pick the k smallest?

level: middleimportance: must knowfreq 60%

basics

~20 s

Expected O(n) is an average over pivot choices, not a per-call guarantee: naive pivot rules degrade to O(n^2) on sorted or duplicate-heavy input. Quickselect also permutes the caller's data in place and needs the entire input resident.

open as a page

Why does inserting into a heap usually finish far sooner than extracting, if both are O(log n)?

level: middleimportance: should knowfreq 48%

basics

~20 s

Both are O(log n) in the worst case, but insert's sift-up usually stops after a comparison or two, because most nodes already live in the bottom levels. Extract's sift-down starts a bottom-of-the-tree key at the root and usually travels most of the height.

open as a page

In this bottom-up heapify loop, why must sift-down run from the last internal node toward index 0?

level: middleimportance: should knowfreq 48%

basics

~20 s

Sift-down only works when both subtrees below a node are already valid heaps. Children sit at higher indices than their parent, so counting indices down guarantees that precondition; running the loop upward can leave the heap property violated.

open as a page

Why must a binary heap be a complete tree with the last level filled left to right?

level: middleimportance: should knowfreq 58%

basics

~20 s

Completeness is what makes the implicit array work: nodes fill slots 0 to n-1 with no gaps, so index arithmetic replaces pointers and the height stays floor(log2 n). Allow a hole and child indices address emptiness.

open as a page

In a priority queue, what order do two equal-priority items come out in, and can you rely on it?

level: middleimportance: should knowfreq 50%

basics

~20 s

Unspecified, and you cannot rely on it. Extract-top promises to return an item of top priority, not a particular one, so items that tie come out in an order set by the operation history. Break ties with a monotonically increasing sequence number to get arrival order.

open as a page

In a heap-based k-way merge, which two boundary conditions crash the naive loop?

level: middleimportance: should knowfreq 48%

basics

~20 s

Seeding from a source that is empty, and refilling from a source that has just run out. Both read past the end of a sequence. Guard the seed loop with an emptiness check and the refill with a has-next check.

open as a page

In a d-ary heap, why doesn't a shallower tree automatically make extract-min faster?

level: middleimportance: should knowfreq 32%

basics

~20 s

Raising d shrinks the height to log_d n, but every sift-down level must find the smallest of d children instead of two. Extract-min cost grows as d over log d, so a wider heap makes sift-up cheaper and sift-down dearer.

open as a page

What does an indexed heap's position map buy you when a queued item's priority changes?

level: middleimportance: should knowfreq 45%

basics

~20 s

An indexed heap maps each element's identity to its current array slot, so reprioritizing a queued element costs O(log n): O(1) to locate it, then one sift. A plain heap must scan O(n) to find it first.

open as a page

A service seeds a dispatch heap for a million pending payments with a one-by-one insert loop — do you flag it in review?

level: seniorimportance: should knowfreq 40%

basics

~20 s

Flag it, but on facts rather than asymptotics: with every record in hand, the bulk build is a one-line change from O(n log n) worst case to O(n). Check first how records arrive and what share of the job construction is.

open as a page

A teammate wants an in-order walk of a max-heap to list ratings descending — why does that fail?

level: seniorimportance: should knowfreq 52%

basics

~20 s

The heap invariant relates a node only to its own children, never one subtree to another, so an in-order walk emits an arbitrary sequence. Ranked output costs O(n log n) by removing the root n times.

open as a page

In a priority queue, what must you do to change the ordering rule while items are already queued?

level: seniorimportance: should knowfreq 38%

basics

~20 s

Rebuild the queue. Every queued item sits at a position justified by the old comparison, so swapping the rule in place leaves the structure inconsistent. Take the existing elements and re-establish the invariant under the new rule, which costs O(n) with a bulk build.

open as a page

A review shows a priority queue's arbitrary-element removal called in a loop — what do you flag?

level: seniorimportance: should knowfreq 44%

basics

~20 s

Removing a named element from a heap-backed queue is O(n): only the top is addressable, so the element must be found by scanning. Called once per cancelled item in a loop, that is quadratic work hidden behind an innocuous-looking call.

open as a page

In a k-way merge heap, what ordering is guaranteed among equal keys from different sources?

level: seniorimportance: should knowfreq 44%

basics

~20 s

None. A heap is not stable, so equal keys from different sources come out in an order determined by internal array positions. Order within a single source is preserved automatically; across sources you must extend the comparison key to get determinism.

open as a page

showing 1–30 of 43