Why is a heap's replace-top cheaper than an extract followed by an insert?
answer
- count the passes over the tree height
- what does extract lift into the root?
- the arrival can go straight to the top
- one sift-down instead of down-then-up
- check whether the arrival even beats the top
basics
~20 sReplace-top overwrites the root with the new key and runs a single sift-down. Extract-then-insert runs a sift-down to repair the removal and then a sift-up for the arrival — about twice the tree traversal, plus a needless shrink and regrow of the structure.
solid answer
~50 sExtract-then-insert does two full passes over the height. The extraction lifts the last element to the root and sinks it; the insertion then places the new record at the bottom and lifts it back up — often through the very positions the first pass just rearranged. Replace-top collapses that: write the arriving key straight into the root, return the old top, and sift down once. Both are O(log n), so this is a constant-factor win of roughly two, not a complexity change, and it also avoids the size churn at the tail of the structure. It matters on a hot streaming path where every arrival displaces the current top and comparisons are not free — a composite priority with a tie-breaker, say. On a low-rate board with cheap comparisons, it is noise; measure before adopting it.
go deeper
Know that removing the top and adding a record are each O(log n), and that doing them as one combined operation is possible. The details are not expected of you yet.
Explain why one sift-down suffices: overwriting the root leaves both subtrees valid, which is exactly sift-down's precondition. Contrast that with the sift-down plus sift-up that the two-step form performs.
Show judgment, not just the trick: name it as a constant-factor win, say which workload shape earns it (high arrival rate, expensive comparisons, fixed-size board), and add the guard that skips the heap entirely when the arrival cannot beat the top.
Own the call on whether a hand-tuned variant belongs in the codebase at all — weigh the measured gain against a plain two-step form that every future reader recognises, and insist the structure is proven to be on the critical path first.
## The pattern this exists for Some workloads never grow or shrink their heap. A monitoring board holds the N most urgent records; every arrival that qualifies pushes one record out. A sliding window keeps a fixed roster. In all of them the operation is really *one* logical action — **swap the top for a new record** — and expressing it as "remove, then add" makes the structure do twice the work. ## What extract-then-insert actually costs Walk it on a fixed-size triage board of `n` records: 1. **Extract.** Return the root. Move the last element into the root slot, shrink to `n-1`, sift it down. That element came from the bottom, so it is typically large and typically sinks nearly the full height, at up to two comparisons per level. 2. **Insert.** Put the arriving record in the now-free slot at the bottom, grow back to `n`, sift it up, one comparison per level until it loses. Two traversals of the same height, and they partly undo each other: the first pass drags a bottom key up to the root and pushes it back down; the second drags a new key up from the bottom. ## What replace-top costs 1. Save the root's value to return. 2. Write the arriving record **directly into the root slot** — the size never changes. 3. Sift down once. One traversal. The heap property holds afterwards for the usual sift-down reason: both subtrees of the root were already valid heaps and only the root was disturbed, which is exactly sift-down's precondition. So the win is: **one sift-down instead of a sift-down plus a sift-up**, plus no shrink-and-regrow at the tail. Roughly a factor of two on the heap work. ## Be precise about what improved Both forms are O(log n). Replace-top does **not** change the complexity class, and a candidate who claims it turns the operation constant-time has made the classic direction error — confusing a constant-factor improvement with an asymptotic one. What actually improved is: - **Comparisons**, roughly halved — the lever that grows when a comparison is expensive, e.g. a priority that falls back to an arrival timestamp, or keys that are long identifiers. - **Structural churn**, eliminated — no size change, no touching the tail of the backing storage. - **Atomicity of intent**, which is the underrated one: the heap is never briefly in the `n-1` state, so there is no window in which a concurrent reader or a mid-sequence failure sees a board with a missing record. ## The ordering variant, and the free case There are two distinct pairings, and they are not interchangeable: - **Replace (pop-then-push semantics):** return the current top, then the arrival joins the heap. Always one sift-down. - **Push-then-pop semantics:** the arrival joins first, then the extreme is removed. Here a genuine shortcut exists — if the arriving key is already the extreme (smaller than the current root in a min-heap), the correct answer is the arriving key itself and **the heap need not be touched at all**. One comparison, no traversal, O(1). On a monitoring board keeping the N most urgent records, most arrivals are *not* urgent enough to belong, so this guard skips the heap entirely for the common case — a far bigger win than halving the sift. Getting the two orderings mixed up is a correctness bug, not a performance one: they return different records when the arrival ties or beats the current top. ## Failure modes to name - **Overwriting the root and forgetting the sift-down.** The invariant is violated at the top and the structure never self-repairs; every later extraction can return out-of-order records, with no error at the point of damage. - **Assuming the new key always sinks to a leaf.** It may stop at the root immediately — a key more urgent than both children stays put after two comparisons, and the loop must handle that as the normal case. - **Reaching for it first.** This is a constant-factor optimisation on one structure. If the dispatch path is dominated by serialisation or storage, halving the comparisons buys nothing. The senior move is to establish the heap is on the critical path, then apply it; the principal move is to ask whether a hand-tuned variant is worth the maintenance burden versus a plain, obviously-correct extract-then-insert that every reader recognises. ## The answer in one breath "Same O(log n), half the traversal: write the arrival at the root and sift down once instead of sinking a bottom element and then lifting a new one. It also keeps the size constant. And if the semantics are push-then-pop, check whether the arrival beats the top first — then it costs nothing at all."
- If the arriving key would immediately become the top again, what is the cheapest correct handling?Under push-then-pop semantics — arrival joins, then the extreme is removed — an arriving key at least as extreme as the current root is itself the answer, so you return it and leave the heap completely untouched. One comparison, no traversal. On a board that keeps only the most urgent N records this is the common path, and it beats any sift-count optimisation.
- Does replace-top improve the asymptotic complexity?No. Both replace-top and extract-then-insert are O(log n) because both are bounded by the tree's height. Replace-top halves the traversal and removes the size churn — a constant-factor and allocation win. Presenting it as a complexity improvement is the direction error interviewers listen for; present it as a measured optimisation for a hot path instead.
- What breaks if the root is overwritten and the sift-down is skipped?The heap property is violated at the root and nothing ever repairs it. Peek starts returning a record that is not the extreme, and every subsequent extraction can hand back out-of-order records — silently, far from the code that caused it. The check that catches it is a full parent-versus-children assertion after a randomised operation sequence, not a spot check on one dequeue.
Instead of taking the top card off the board, closing the gap, and then filing a new card up from the bottom, you write the new card straight over the top slot and let it settle once.
saying these in an interview costs you the question
- Claiming replace-top changes the complexity class
- Overwriting the root without sifting down
- Assuming the arriving key always sinks to a leaf
- Confusing pop-then-push with push-then-pop semantics
- Chasing the constant factor before profiling the path