Binary heap visualizer
A heap keeps the smallest (or largest) element at the top and finds the next one in a few swaps. Insert values, extract the root, build a heap from an array and run heapsort, and watch every comparison and swap on the tree and on the array it is stored in. Below it: how each operation works, why building a heap is linear, and where heaps are used.
Children of index i are at 2i + 1 and 2i + 2; its parent is at ⌊(i − 1) / 2⌋.
- –The heap was built from [42, 17, 8, 23, 5, 31, 12, 19, 3, 27]. Insert a value or extract the min to begin.
c = comparisons, s = swaps.
- Elements
- 10 of 31
- Height (levels below the root)
- 3
- Most swaps an insert can need
- 3
- Pairs out of order now
- 0
How to use the simulator
The heap starts as a min-heap built from ten values. Type a number and press Insert, or press Extract min to remove the root. Every operation plays step by step: the highlighted nodes are the ones being compared or swapped, and the sentence under the controls says what happened and why. Use Back, Next and Play to move through the steps, and switch to a max-heap to see the same rules with the order reversed.
- Build from random array runs Floyd’s bottom-up build-heap on twelve random values; compare its comparison count with inserting the same values one by one.
- Heapsort sorts a copy of the heap in place; watch the sorted part grow at the end of the array.
- Insert a value smaller than every other in a min-heap and count the swaps: it climbs all the way to the root.
The operations follow the textbook algorithms. Inserts produce exactly the same array as Python’s heapq.heappush, and extracting everything returns the values in the same order as heapq.heappop; both were checked on 200 random inputs, for min-heaps and max-heaps.
What is a binary heap?
A binary heap is a binary tree with two rules. Its shape is complete: every level is full except possibly the last, which fills from left to right. And it has the heap property: in a min-heap every parent is less than or equal to its children, so the smallest value is at the root; in a max-heap every parent is greater than or equal to its children.
Nothing is said about the order of siblings or of different branches, which is what makes a heap cheap to maintain. It cannot find an arbitrary value quickly or list values in order, but it always knows the minimum (or maximum), and it can add a value or remove the top in time proportional to the tree’s height. That is exactly what a priority queue needs.
J. W. J. Williams introduced the binary heap in 1964 as the data structure behind heapsort, and Robert Floyd published the linear-time way to build one the same year.
Storing a tree in an array
Because a complete tree has no gaps, its nodes can be numbered level by level, left to right, and stored in that order in an array. With indexes starting at 0, the node at index i has its children at 2i + 1 and 2i + 2 and its parent at ⌊(i − 1) / 2⌋. No pointers are stored, the array is contiguous in memory, and adding a node at the bottom of the tree is just appending to the array. (Some textbooks start indexes at 1, giving children 2i and 2i + 1 and parent ⌊i / 2⌋.)
The simulator draws both views of the same data: the tree, and below it the array with each node’s index. A tree with n nodes has ⌊log₂ n⌋ levels below the root, so a heap of a million elements is only 19 levels deep.
Insert: sift-up
To insert, put the new value in the next free slot, the end of the array, which keeps the tree complete. The only place the heap property can now fail is between the new value and its parent. If the new value belongs above its parent (it is smaller, in a min-heap), swap them and repeat from the parent’s position. Stop when the parent is in order or the value reaches the root. This is called sift-up, also bubble-up or percolate-up, and it does at most one comparison and one swap per level.
Inserting 5, 3, 8 and 1 into an empty min-heap, step by step in the model:
| Insert | Array afterwards | Comparisons | Swaps |
|---|---|---|---|
| 5 | [5] | 0 | 0 |
| 3 | [3, 5] | 1 | 1 |
| 8 | [3, 5, 8] | 1 | 0 |
| 1 | [1, 3, 8, 5] | 2 | 2 |
Inserting 1 last moves it from index 3 to the root in two swaps, because it is smaller than everything on its path.
Extract: sift-down
The root holds the minimum. To remove it, take the root out, move the last element of the array into the root, and shrink the array by one. The tree is complete again, but the new root is probably too large. Compare it with its smaller child (larger, in a max-heap); if the child belongs above it, swap them and repeat one level down. This is sift-down, also called heapify-down. Each level costs two comparisons, one to pick the child and one to compare with it.
Extracting the minimum from the heap above returns 1 and leaves [3, 5, 8], after 2 comparisons and 1 swap.
Python’s heapq.heappop uses a variation: it moves the smaller child up all the way to a leaf without comparing with the moved element, then sifts that element back up a little. Its source notes that this saves comparisons on average, since the element taken from the end usually belongs near the bottom. The values come out in the same order; the arrays in between can differ.
Building a heap in linear time
Turning an unsorted array into a heap by inserting its elements one at a time costs O(n log n) in the worst case. Floyd’s method is faster: treat the array as a complete tree as it stands, notice that every leaf (the second half of the array) is already a one-element heap, and sift down each parent, from the last parent back to the root. When a node is sifted down, both its subtrees are already heaps.
Most nodes are near the bottom and can only move a short distance: half are leaves and do nothing, a quarter move at most one level, an eighth at most two. Summed up, the work is O(n), and the number of comparisons stays below 2n. Counting comparisons in the model, on the same values in both cases:
| Elements | Floyd’s build-heap | One insert at a time | 2n |
|---|---|---|---|
| 15 | 18 | 30 | 30 |
| 63 | 98 | 149 | 126 |
| 255 | 454 | 628 | 510 |
| 1,023 | 1,864 | 2,646 | 2,046 |
Repeated insertion can be cheaper on friendly input (here the values are a scrambled sequence), but its worst case, an input in reverse order, makes every insert climb to the root. Floyd’s bound holds for every input. Python’s heapq.heapify and C++’s std::make_heap build heaps bottom-up in linear time.
Heapsort
Heapsort sorts an array in place with a heap. Build a max-heap from the array; the largest value is now at index 0. Swap it with the last element of the heap, shrink the heap by one so that value is fixed in its final place, and sift down the new root. Repeat until the heap is empty. The array ends up in ascending order (a min-heap gives descending order, as the simulator shows when you heapsort a min-heap).
Heapsort runs in O(n log n) time in the worst case and needs only O(1) extra memory, which few sorts manage at once. It is not stable, and in practice it is usually slower than a good quicksort because its accesses jump around the array and miss the cache. Its guaranteed worst case is why introsort, the algorithm behind many C++ std::sort implementations, falls back to heapsort when quicksort’s recursion gets too deep.
Complexity
| Operation | Time | How |
|---|---|---|
| Peek at min or max | O(1) | Read index 0 |
| Insert | O(log n) | Append, sift-up |
| Extract min or max | O(log n) | Move last to root, sift-down |
| Build from n values | O(n) | Floyd’s bottom-up sift-down |
| Change a key (index known) | O(log n) | Sift up or down from its index |
| Find an arbitrary value | O(n) | No order to search by |
| Heapsort | O(n log n) | n extracts, in place |
Average-case insert is O(1): a random new value usually belongs near the bottom, and on average sift-up moves it only a constant number of levels.
Priority queues and where heaps are used
A priority queue lets you add items with priorities and always take the highest-priority item next. The binary heap is its standard implementation, and it appears wherever “what next?” has to be answered quickly:
- Graph algorithms: Dijkstra’s shortest paths, Prim’s minimum spanning tree and A* search take the closest unvisited node from a heap.
- Scheduling: timers and event simulations pop the earliest deadline; operating system and job schedulers pick the next task by priority.
- Top-k: keep a min-heap of size k while streaming values to find the k largest in O(n log k) time and O(k) memory.
- Merging: merging k sorted lists or files, as databases and external sorts do, keeps the head of each list in a heap of size k.
- Running median: a max-heap of the lower half and a min-heap of the upper half give the median of a stream at any moment.
- Compression: building a Huffman code repeatedly combines the two least frequent symbols, taken from a min-heap.
Heaps in standard libraries
| Language | Type | Default order |
|---|---|---|
| Python | heapq functions on a list | Min-heap |
| Java | java.util.PriorityQueue | Min-heap (natural order) |
| C++ | std::priority_queue, std::make_heap | Max-heap |
| Go | container/heap on your own type | Whatever Less says |
| Rust | std::collections::BinaryHeap | Max-heap |
For the opposite order, pass a comparator (Java, C++), wrap values in Reverse (Rust), or store negated keys (Python). None of these support removing or changing an arbitrary element efficiently, since they do not track where each element sits; algorithms that need decrease-key usually push a new entry and skip stale ones when they are popped.
Other kinds of heap
A d-ary heap gives each node d children instead of two. The tree is shallower, so inserts and decrease-key are faster, while extract does more comparisons per level; 4-ary heaps are often faster in practice thanks to better cache use. Binomial, pairing and Fibonacci heaps support merging two heaps quickly; the Fibonacci heap (Fredman and Tarjan, 1987) does decrease-key in O(1) amortised time, which improves the theoretical bound of Dijkstra’s algorithm, though its constant factors mean binary heaps usually win in practice.
Heaps in interviews
Heap questions are common in coding interviews, usually as a tool rather than a data structure to implement: kth largest element, top k frequent elements, k closest points, merge k sorted lists, task scheduling, meeting rooms, and the median of a data stream with two heaps. Know which library heap your language provides and its default order, the O(n log k) cost of keeping a size-k heap, and why that beats sorting when k is small.
When asked to implement one, write the array index formulas, sift-up and sift-down, and mention that build-heap is O(n). The classic follow-up is the proof sketch of that bound, or why heapsort is not stable.
Heap questions and answers
What is a binary heap?
A binary heap is a complete binary tree in which every parent is ordered before its children: no larger than them in a min-heap, no smaller in a max-heap. The smallest (or largest) element is therefore always at the root. Because the tree is complete, it is stored in a plain array without pointers: the children of index i are at 2i + 1 and 2i + 2, and its parent at (i − 1) / 2 rounded down.
What is the time complexity of heap operations?
Reading the minimum or maximum is O(1). Insert and extract are O(log n), because an element moves at most the height of the tree, which is about log₂ n. Building a heap from n unsorted elements with Floyd’s method is O(n), and heapsort is O(n log n) in the worst case and sorts in place.
How does inserting into a heap work?
The new element goes into the next free position at the bottom of the tree, which is the end of the array, so the tree stays complete. Then it is compared with its parent and swapped upward while it is out of order. This is called sift-up, bubble-up or percolate-up, and it stops at the root or as soon as the parent is in the right order.
How do you remove the minimum from a min-heap?
Take the root, which is the minimum. Move the last element of the array into the root, shrinking the heap by one, and then sift it down: compare it with the smaller of its children and swap while it is larger. When it is no larger than both children, or has none, the heap is valid again.
Why is building a heap O(n) and not O(n log n)?
Floyd’s bottom-up method sifts down each parent, starting from the last one. Most nodes are near the bottom and can only move a level or two: half the nodes are leaves and do no work, a quarter move at most one level, and so on. The total work is bounded by about 2n comparisons, which the simulator’s counts confirm. Inserting the elements one by one instead costs O(n log n) in the worst case.
What is the difference between a heap and a binary search tree?
A binary search tree orders every left subtree before every right subtree, so it can find any key and list keys in order. A heap only orders parents before children, which is weaker: it can only find the minimum (or maximum) quickly, but it is cheaper to maintain, fits in an array, and has no balancing work.
What is a priority queue?
A priority queue is an abstract data type where each element has a priority and you always remove the highest-priority one next. A binary heap is the usual implementation: Python’s heapq, Java’s PriorityQueue, C++’s std::priority_queue and Rust’s BinaryHeap are all binary heaps. Priority queues drive Dijkstra’s algorithm, event simulations, task schedulers and top-k queries.
Is Python heapq a min-heap or a max-heap?
A min-heap: heapq.heappop always returns the smallest element. The usual way to get a max-heap is to push negated values (or tuples with a negated priority) and negate them again when popping.
Further reading
- Williams, Communications of the ACM, 1964Algorithm 232: HeapsortThe original binary heap and heapsort.
- Floyd, Communications of the ACM, 1964Algorithm 245: Treesort 3The bottom-up construction that builds a heap in linear time.
- Python documentationheapq: Heap queue algorithmThe standard library heap, with notes on its implementation and priority-queue recipes.
- Fredman and Tarjan, Journal of the ACM, 1987Fibonacci heaps and their uses in improved network optimization algorithmsThe heap with O(1) amortised decrease-key.
- SemicolonyDijkstra’s algorithm simulatorA priority queue at work, picking the next closest node.