skip to content

Heap, sorted list, or balanced tree for a live auction's top bid and next-k view?

level: seniorimportance: should knowfreq 58%

answer

  1. Write the operation counts down first
  2. Which operation has the highest volume
  3. Sorted arrays shift on every insert
  4. A heap is not a sorted array
  5. Ordered walks are what trees are for

basics

~20 s

Count the operations first. Bids arrive constantly, the top is read constantly, the next-k view rarely. That profile kills the sorted list's O(n) inserts; a heap fits while the top read dominates, a balanced tree once the ordered next-k view turns hot.

solid answer

~50 s

The colleague saying "a sorted list is simpler" is right about the code and wrong about the workload: keeping an array sorted costs O(n) per bid because elements shift, and bids are the highest-volume operation here. A binary max-heap gives O(log n) insert and the top in O(1), fitting an insert-heavy, peek-heavy profile — but its array is not sorted, so the next k in order means extracting from a copy, roughly O(k log n). A balanced search tree gives O(log n) insert, the maximum in O(log n) (O(1) with a cached pointer), and the next k descending in O(log n + k) with no copy. Heap when the runners-up view is rare; tree once it is rendered often, or when bids can be retracted, since a tree deletes by key while a heap needs a side index.

go deeper

for a junior

Know that a heap gives you the largest element immediately but keeps everything else only loosely ordered, and that keeping an array sorted costs work on every insertion.

for a middle

Explain the per-operation costs of all three and why the heap's parent-child invariant is weaker than total order. Be precise that reading k items in order from a heap needs extraction, not a slice.

for a senior

Lead with the operation profile, pick against the highest-volume operation, and name the condition that flips the decision. Bring up retraction and what it costs each candidate before being asked.

for a principal

Own the argument with the colleague defending simplicity: attach their claim to a bound on n and a measured rate, and decide what the team maintains long-term rather than what looks optimal today.

## Start from the operation counts, not the structure names A live auction page needs two things from its bid store: the current highest bid, read on every render and every websocket push, and — when a viewer expands a panel — the next few bids below it, in order. Bids themselves arrive continuously, and occasionally a bid is retracted. Write the profile down before choosing: - insert: very high volume - read the single maximum: very high volume - read the next k in order: low volume, small k - delete an arbitrary element: rare but required - full ordering of everything: never That last line matters as much as the first. A structure that maintains total order pays for a property nobody reads. ## The three candidates against that profile **Sorted array.** Finding the insertion point is a binary search, O(log n), but placing the element shifts everything after it: O(n) per bid. The top is at a known end, O(1); the next k are the k adjacent entries, O(k), with excellent locality. It is genuinely the simplest code and the right answer for a read-mostly list — but here the highest-volume operation is exactly the one it does worst. On a hot auction with tens of thousands of live bids, every incoming bid moves memory proportional to the whole set. A sorted linked list is not a rescue: it removes the shifting but reintroduces an O(n) walk to find the insertion point, because there is no random access to binary-search over. **Binary max-heap.** A complete binary tree in an array, with the invariant that each node is at least as large as its children. Insert appends and sifts up, O(log n) worst case; the maximum is the root, O(1) to read. This matches the two high-volume operations precisely — which is the whole argument against the sorted list, and it is an argument about the profile rather than about elegance. The heap's weakness is exactly the operation the sorted list did well. The heap invariant is only parent-versus-child; siblings and cousins are unordered, so the array is *not* sorted and the second largest element is merely "one of the root's two children". Producing k items in descending order means repeatedly extracting the root, which mutates the structure — so you copy first and extract from the copy, roughly O(k log n) on top of the copy, or you run a bounded search over the top of the array. When k is 5 and the panel opens rarely, that is fine. When the panel is on every render, it is the wrong structure. Arbitrary deletion is the heap's other weak point: retracting a specific bidder's bid requires finding it, and nothing in the heap tells you where it is. The standard fix is a side map from bid identity to array position, kept updated on every sift — a second structure with an invariant to maintain, which is real complexity to hand to a team. **Balanced search tree.** Ordered by bid value with a balancing rule holding the height at O(log n). Insert and delete-by-key are O(log n); the maximum is the rightmost node, O(log n) to reach or O(1) if you cache a pointer and update it on mutation; the next k in descending order is a reverse in-order walk, O(log n + k), no copy and no mutation. It costs more per insert in constants than the heap and more memory per element, and it is more machinery than either alternative. | Operation | Sorted array | Binary max-heap | Balanced tree | | --- | --- | --- | --- | | insert a bid | O(n) shift | O(log n) | O(log n) | | read the top | O(1) | O(1) | O(log n), O(1) cached | | next k in order | O(k) | ~O(k log n) on a copy | O(log n + k) | | delete a named bid | O(n) | O(log n) with a side index | O(log n) | ## Defending the choice out loud The answer an interviewer wants is not a structure, it is a ratio: how often is the runners-up panel opened relative to bid arrivals, and are retractions in scope? If the panel is rare and retraction is handled by tombstoning rather than removal, the heap is defensible and simpler than a tree. If the panel is rendered with the top bid on every page — which product will ask for eventually — the tree wins on the operation that actually repeats, and the extra constant on insert is cheap next to copying a heap on every render. The sorted list keeps its constituency: a small auction, or a store rebuilt periodically rather than continuously mutated, where n stays in the dozens. At that size the shift is a memory move over a contiguous block and beats both alternatives on constants. "Simpler" is a legitimate argument — it just has to be attached to a bound on n and a measured insert rate, not asserted. ## The distinguishing move Weak answers name a structure first and justify it afterwards. Strong answers state the profile, note which operation has the highest volume, and only then choose — and they say what would change the choice. Here the switch condition is crisp: the moment the ordered runners-up view moves onto the render path, the heap stops fitting.

  • Your colleague says the second largest bid is simply the heap root's larger child. Are they right?
    Only for the second largest specifically, and only because the true runner-up must be a child of the root. It does not extend: the third largest can be anywhere in the top few levels, and the heap invariant orders parents against children only. Reading k in order still needs extraction from a copy.
  • A bidder retracts a specific bid. How does that change the comparison?
    It pushes toward the tree. Deletion by key is a normal O(log n) tree operation, while a heap has no way to locate an arbitrary element and needs a side map from identity to array position, updated on every sift. That is a second structure with an invariant, which is exactly the complexity the heap was supposed to save.
  • When is the sorted list actually the right answer here?
    When n is small and bounded, or the store is rebuilt periodically rather than mutated continuously. A shift over a contiguous block of a few dozen entries beats pointer chasing on constants, and the code is simpler. State the bound you are relying on, and add a test that fails if it is exceeded.

A heap is a tournament bracket that always shows you the champion, but you cannot read second place off it without replaying matches. A tree keeps the whole standings in order all the time.

saying these in an interview costs you the question

  • Names a structure before stating the operation profile
  • Believes a heap's array is in sorted order
  • Ignores the shift cost of sorted-array inserts
  • Assumes a heap can delete an arbitrary element cheaply
  • Maintains total ordering that nothing ever reads

context