A scheduler holds thousands of pending tasks. New work keeps arriving, and the earliest deadline must remain cheap to retrieve.

A heap gets that speed by maintaining less order than a sorted list. It guarantees only that the root is the smallest (or largest) element. Everything below it remains partially ordered. In a binary min-heap, the second-smallest item is the smaller root child when both exist. Arbitrary successor and kth-rank lookup still require a scan, and iteration is not sorted.

Core shape: complete binary tree → heap-order property (min-heap: parent ≤ both children) → packed implicitly into an array → only the root is the extreme

Visualization

Use the controls to insert and extract repeatedly. The visualizer preserves the current heap between operations, highlights the active sift path, and restores [3, 5, 8, 9] on reset.

Representation and Invariants

A binary heap is a complete binary tree: every level is full except possibly the last, which fills left to right with no gaps. That completeness is what makes an implicit array representation valid — with no holes, the tree maps onto contiguous indices by arithmetic instead of pointers.

For a node at index i:

  • its children are at 2i + 1 and 2i + 2,
  • its parent is at (i - 1) / 2 (integer division),
  • the root is index 0, and the last element is the rightmost leaf.

No per-node object, no child pointers, no allocation per element — just one array plus a count. Three operations move state:

  • insert appends the new value at the end (index count), then sifts up: while the value is smaller than its parent, swap the two and follow the parent index toward the root.
  • extract-min reads index 0, moves the last element into the root, shrinks the count, then sifts down: repeatedly swap with the smaller of its two children until neither child is smaller.
  • peek returns index 0 without touching the array.

The heap-order invariant is local: every parent is both of its children (min-heap; a max-heap reverses the comparison). Sift-up restores it along a single root-ward path after an append; sift-down restores it along a single leaf-ward path after the root is replaced. The invariant says nothing about order across subtrees, so arbitrary ranks cannot be read directly from array positions.

Complexity
  • insert: O(log n) amortized; O(n) worst case
n
number of elements currently stored in the heap

Boundaries

The array holds a partial order, not a sorted sequence. That single boundary explains the missing operations.

  • A heap answers “what is the minimum,” not “where is x.”
  • Efficient arbitrary delete and decrease-key need an external position map. The operations touch a node by position, but the heap exposes elements only by heap-order, not by identity. In .NET 9 and .NET 10, System.Collections.Generic.PriorityQueue.Remove performs that linear scan and can be followed by Enqueue to emulate a priority update, but the type has no DecreaseKey. Lazy deletion — enqueue the new priority and skip stale entries on dequeue — avoids the scan when duplicate entries are acceptable.

Diagram and C# Implementation

References