A complete binary tree stored in an array, satisfying the heap property: every node is (min-heap) or (max-heap) its children.
Array layout
For a 0-indexed array: node has children and , and parent . No pointers, perfect cache locality.
| Operation | Cost |
|---|---|
top | |
push | — append, then sift up |
pop | — move the last element to the root, sift down |
build from an array | — sift down from the last internal node backwards |
decrease-key | , but needs an index map |
merge two heaps | — binary heaps do not merge cheaply |
Build is , not : most nodes are near the leaves and sift down only a little. The sum converges to .
In C++
priority_queue<int> maxHeap; // max by default
priority_queue<int, vector<int>, greater<int>> minHeap; // min
priority_queue<pair<long long,int>, vector<pair<long long,int>>, greater<>> pq; // Dijkstra
// custom comparator
auto cmp = [](const Item& a, const Item& b) { return a.cost > b.cost; }; // min-heap
priority_queue<Item, vector<Item>, decltype(cmp)> q(cmp);
// build in O(n)
priority_queue<int> h(a.begin(), a.end());The comparator is inverted
priority_queueputs the element the comparator considers largest on top. Sogreater<>yields a min-heap, and a customcmpreturninga > balso yields a min-heap. This trips up nearly everyone at least once.
No decrease-key — use lazy deletion instead
std::priority_queue cannot update an element. The standard workaround, and the one used in every Dijkstra implementation:
pq.push({newDist, v}); // push a new entry, leave the stale one
...
auto [d, u] = pq.top(); pq.pop();
if (d > dist[u]) continue; // skip stale entriesThe queue grows to instead of , but the complexity is unchanged and the code is much simpler than an indexed heap.
When you genuinely need decrease-key (or erase), use std::set as a heap — for everything including deletion, at the cost of a worse constant.
The heap family
| Heap | push | pop | decrease-key | merge |
|---|---|---|---|---|
| Binary | ||||
| Binomial | ||||
| Fibonacci | am. | am. | am. | |
| Pairing | am. | am. | ||
| Leftist / skew | — |
Binary heaps win in practice on constant factor; the others exist for their merge or decrease-key. See Advanced Heaps.
Uses
- Dijkstra, Prim, A*
- Huffman coding — repeatedly merge the two smallest
- Heap sort — , in place, not stable
- -th largest, top — keep a size- min-heap
- Merging sorted lists — heap of list heads,
- Median of a stream — two heaps, a max-heap for the lower half and a min-heap for the upper
- Event simulation / sweep lines — process events in time order
- Slope trick — the entire technique is two heaps
The two-heap median trick
Maintain lo (max-heap, smaller half) and hi (min-heap, larger half), rebalancing so their sizes differ by at most 1. The median is lo.top() (odd count) or the average of both tops (even). per insertion — a fifteen-line answer to “running median”, which is otherwise awkward.
See also: Advanced Heaps · Sorting · Dijkstra