Min/Max Heap Visualization — Step by Step
Complete binary tree where parent is always smaller (min) or larger (max) than its children.
// quick answer
Min/Max Heap is a data structures structure that runs in O(log n) time on average with O(n) space. Complete binary tree where parent is always smaller (min) or larger (max) than its children.
How Min/Max Heap Works
A Heap is a complete binary tree stored as an array, where the parent node satisfies the heap property: smaller than both children (min-heap) or larger (max-heap). Insert uses bubble-up, extract uses bubble-down. Used in priority queues and heap sort. O(log n) insert and extract.
Min/Max Heap Step by Step
A complete tree that lives in an array
A heap is a binary tree with a strict *shape* rule: every level is completely full except possibly the last, which fills left to right. That completeness means the tree can live in a plain array with no pointers at all. The node at index i has children at 2i + 1 and 2i + 2, and its parent at ⌊(i − 1) / 2⌋. Moving up or down the tree is pure index arithmetic — no allocation, cache-friendly, and impossible to unbalance. The visualizer draws the familiar tree shape, but keep in mind that underneath, the entire structure is just an array being indexed cleverly.
The heap property: ordered, but only vertically
The second rule is the heap property: in a max-heap every parent is greater than or equal to its children; a min-heap is the mirror image. Crucially, that is the *only* ordering. Siblings have no relationship, and a node deep in the left subtree may exceed everything in the right subtree. So a heap is emphatically not sorted — it guarantees exactly one thing globally: the root is the maximum (or minimum). That deceptively weak guarantee, maintained in O(log n) per operation, is precisely what a priority queue needs, and asking a heap for anything more than its root is asking the wrong structure.
Insert: sift up
Insertion appends the new value at the end of the array — the only position that keeps the tree complete — then repairs the heap property by sifting up. Compare the value with its parent and swap while it beats the parent: bigger in a max-heap, smaller in a min-heap. The value climbs its ancestor chain until a parent wins or it reaches the root. Because a complete tree of n nodes has height ⌊log₂ n⌋, this costs at most O(log n) swaps, and usually far fewer. The visualizer's demo inserts every input value one at a time, so you can watch each sift-up play out swap by swap.
Extract: sift down
Extraction always removes the root — the extreme element. But the shape rule says the *last* array slot is the one that must disappear, so: save the root, move the last element into index 0, shrink the array, then sift down. The displaced value repeatedly swaps with its larger child (in a max-heap) until both children are smaller or it hits the bottom — again O(log n). The demo runner inserts all values and then extracts every single one, and the extracted roots come out in sorted order. That is no coincidence; it is heapsort in embryo, as the last section shows.
Build-heap: O(n), surprisingly
Turning an arbitrary array into a heap does not require n separate inserts. Bottom-up heapify starts at the last internal node — index ⌊n/2⌋ − 1 — and sifts down each node, moving backward to the root. The leaves, which make up half the array, need no work at all. The total cost is O(n), not O(n log n): most nodes sit near the bottom with almost nothing below them to sift through, and summing (nodes per level × height below that level) converges to a constant times n. This linear build step is what makes heapsort's setup free, and it is a classic interview question in its own right.
Heapsort and priority queues
Two famous applications fall straight out of these operations. Build a max-heap, then repeatedly swap the root with the last element of a shrinking prefix and sift down: the array sorts itself in place, largest values settling at the end — heapsort, O(n log n) worst case with O(1) extra space. Even more important in practice is the priority queue: a heap of pending items where you always pop the most urgent one next. That single abstraction powers Dijkstra's shortest paths, operating-system schedulers, event-driven simulation, Huffman coding, and top-k queries over streams. Whenever code needs 'the best remaining item, with inserts at any time,' a heap is the answer.
Time & Space Complexity
| Best Case | Average Case | Worst Case | Space |
|---|---|---|---|
| O(1) | O(log n) | O(log n) | O(n) |
Min/Max Heap Pseudocode
Heap operations:
insert(value):
add at end, bubble up
bubbleUp(i):
while parent > child (min):
swap with parent
extractMin():
swap root with last
remove last, bubble down
bubbleDown(i):
swap with smallest childPress play in the visualizer above to watch each line execute with live highlighting.
Min/Max HeapCode in JavaScript, Python & Java
JavaScript
function siftUp(a, i) {
while (i > 0) {
const parent = (i - 1) >> 1;
if (a[parent] >= a[i]) break;
[a[parent], a[i]] = [a[i], a[parent]];
i = parent;
}
}
function siftDown(a, i) {
while (true) {
let largest = i;
if (2 * i + 1 < a.length && a[2 * i + 1] > a[largest]) largest = 2 * i + 1;
if (2 * i + 2 < a.length && a[2 * i + 2] > a[largest]) largest = 2 * i + 2;
if (largest === i) break;
[a[i], a[largest]] = [a[largest], a[i]];
i = largest;
}
}
function insert(heap, value) {
heap.push(value);
siftUp(heap, heap.length - 1);
}
function extractMax(heap) {
const max = heap[0];
const last = heap.pop();
if (heap.length > 0) {
heap[0] = last;
siftDown(heap, 0);
}
return max;
}Python
def sift_up(a, i):
while i > 0:
parent = (i - 1) // 2
if a[parent] >= a[i]:
break
a[parent], a[i] = a[i], a[parent]
i = parent
def sift_down(a, i):
n = len(a)
while True:
largest = i
left, right = 2 * i + 1, 2 * i + 2
if left < n and a[left] > a[largest]:
largest = left
if right < n and a[right] > a[largest]:
largest = right
if largest == i:
break
a[i], a[largest] = a[largest], a[i]
i = largest
def insert(heap, value):
heap.append(value)
sift_up(heap, len(heap) - 1)
def extract_max(heap):
maximum = heap[0]
last = heap.pop()
if heap:
heap[0] = last
sift_down(heap, 0)
return maximumJava
import java.util.ArrayList;
import java.util.List;
class MaxHeap {
private final List<Integer> a = new ArrayList<>();
void insert(int value) {
a.add(value);
int i = a.size() - 1;
while (i > 0 && a.get((i - 1) / 2) < a.get(i)) { // sift up
swap((i - 1) / 2, i);
i = (i - 1) / 2;
}
}
int extractMax() {
int max = a.get(0);
a.set(0, a.get(a.size() - 1));
a.remove(a.size() - 1);
int i = 0; // sift down
while (true) {
int largest = i, l = 2 * i + 1, r = 2 * i + 2;
if (l < a.size() && a.get(l) > a.get(largest)) largest = l;
if (r < a.size() && a.get(r) > a.get(largest)) largest = r;
if (largest == i) break;
swap(i, largest);
i = largest;
}
return max;
}
private void swap(int i, int j) {
int t = a.get(i); a.set(i, a.get(j)); a.set(j, t);
}
}When to Use Min/Max Heap
- Priority queues — anywhere you repeatedly need the minimum or maximum while items keep arriving: task schedulers, Dijkstra's algorithm, A* search, event-driven simulation, timer wheels.
- Top-k problems over large or streaming data — keep a k-element heap and process n items in O(n log k), without ever sorting the whole input.
- Merging k sorted lists — a heap of size k always knows which list head comes next, giving an O(n log k) merge.
- Heapsort — when you need guaranteed O(n log n) time with O(1) extra space and can give up stability; most quicksort implementations fall back to it in pathological cases.
- Avoid it when you need to find or delete arbitrary values — membership testing in a heap is O(n). Use a hash table for exact lookup or a BST for ordered search.
- Avoid it when you need sorted iteration over all elements repeatedly — extracting everything destroys the heap; a binary search tree or sorted array serves ordered traversal better. And for plain first-in-first-out, a simple queue is O(1) per operation.
Min/Max Heap — Frequently Asked Questions
Is a heap a sorted structure?
No. A heap only guarantees the parent-child relationship: each parent beats its children (larger in a max-heap, smaller in a min-heap). Siblings are unordered, and the array behind a valid heap is generally not sorted. The only element with a known global position is the root. If you extract elements one by one they do emerge in sorted order, but each extraction costs O(log n) restructuring.
What is the difference between a heap and a binary search tree?
A BST orders horizontally — left subtree smaller, right subtree larger — so it can search for any value in O(log n) and iterate in sorted order. A heap orders only vertically, so it can do just one thing fast: access and remove the extreme element. In exchange, a heap is a pointer-free array, always perfectly compact, with simpler and typically faster operations for the priority-queue use case.
Why is building a heap O(n) and not O(n log n)?
Bottom-up heapify sifts down every internal node, starting from the last one. The cost of each sift is the height below that node, and most nodes are near the bottom where that height is tiny: half the nodes are leaves costing nothing, a quarter can sink at most one level, and so on. The weighted sum across all levels converges to O(n), unlike n repeated inserts, which cost O(n log n).
What is the difference between a min-heap and a max-heap?
Only the comparison direction. A min-heap keeps every parent less than or equal to its children, so the root is the minimum; a max-heap keeps parents greater than or equal, so the root is the maximum. All operations are identical with the comparison flipped, and one can impersonate the other by negating values — a common trick in languages whose standard library ships only a min-heap.
Is a priority queue the same thing as a heap?
Not exactly. A priority queue is an abstract data type — an interface promising insert and remove-highest-priority operations. A heap is the most common concrete implementation of that interface, because it delivers both operations in O(log n) with minimal memory. But priority queues can also be built on sorted lists, balanced trees, or specialized structures like Fibonacci heaps when different performance trade-offs are needed.
Related Algorithms
- Binary Search Tree Visualization — Tree where left child < parent < right child. Supports O(log n) insert, search, and delete.
References & Further Reading
- Williams, J. W. J. (1964) — Algorithm 232: Heapsort — Communications of the ACM, 7(6)
- Wikipedia — Binary heap
- Cormen, Leiserson, Rivest & Stein — Introduction to Algorithms (4th ed., MIT Press)