Binary heap Created 2026-10-13 Updated 2026-10-24
A binary heap represents a priority queue as a complete binary tree obeying a heap order. We use the minimum convention: the priority of every parent in a rooted tree is no greater than the priorities of its children in a rooted tree. Equal priorities are allowed. Each stored entry may be a record carrying a priority key; the numerical example below displays only keys. Reversing the inequalities gives the maximum convention.
The complete binary tree can be stored directly in a zero-indexed array : read its levels from top to bottom, left to right. The root of a tree is at index . The possible children in a rooted tree of index are at and , and an index denotes a present entry only when it is less than . For , its parent in a rooted tree is at , using the floor function. Thus the links of the complete binary tree are determined by arithmetic rather than separately stored pointers.
ConsiderThe children in a rooted tree of index have keys ; those of index have keys ; those of index have keys . The six comparisons , , , , , establish the heap order. At index , the parent in a rooted tree is index , carrying key .
The array is visibly not a sorted array: precedes , and precedes . Nor is the last entry a maximum: it is , whereas the maximum is at index . The heap order compares ancestors and descendants, without imposing an order between separate branches. Nevertheless, following the graph path from the root of a tree to any entry gives a chain of nondecreasing priorities. This short argument proves that
peek can return , a minimum, without inspecting the other entries.Insertion appends an entry to the array, preserving the shape of the complete binary tree, then uses sift up to repair the heap order. Insert key into the displayed binary heap. It is appended at index , and exchanges with indices , , then :The moving key follows ; the keys each move down one level. Only this chain needs repair.
Now apply
extract-min. Save key , move the last key to the root of a tree, and shorten the array to length . Use sift down, always choosing the smaller of the present children in a rooted tree:First exchanges with key at index , since ; then with key at index , since . At index , the possible children in a rooted tree would be indices , both outside the shortened array, so the process stops. The returned key is , and the remaining binary heap is exactly the original one.For a nonempty binary heap with entries, the deepest level is , using the floor function and logarithm. Each exchange moves one level and uses only a bounded number of comparisons. The resulting time complexity bounds, expressed in Big O notation, are:
| Operation | Time complexity | Reason |
|---|---|---|
peek | Read the root of a tree. | |
| Insert | for | Append, then sift up through at most the levels of the complete binary tree. |
extract-min | for | Move the last entry, then sift down through at most those levels. |
| Build from an arbitrary array | Apply sift down from the last index with children in a rooted tree back to index . |
These bounds assume constant-cost indexed access, key comparisons and exchanges, and available array capacity for insertion. Allocating and copying a larger array is a separate cost. Empty and one-entry cases take constant work.
To build a binary heap, begin at index and work backwards. Entries without children in a rooted tree already obey the heap order. Each sift down, also called heapify down, starts with every present smaller rooted tree below it already repaired. Most entries are close to the bottom and can move very little; successively longer repair distances occur for geometrically fewer entries. Summing these distances gives work, rather than charging to every entry. MIT's notes give this bottom-up construction and contrast it with repeated insertion.[ref]
https://ocw.mit.edu/courses/6-006-introduction-to-algorithms-spring-2020/40d4851e550507ca14dc778b9b2266cc_MIT6_006S20_lec8.pdf. MIT 6.006, lecture 8: implicit indices, heap repair and linear build, pp. 3–6
The Dijkstra algorithm additionally needs to decrease the priority of an existing vertex when its tentative distance improves. Given its current index, lowering the key followed by sift up takes time for . An indexed binary heap maintains a separate map from item identity to its current index and updates that map after every exchange. For vertices numbered in a fixed range, the map can be another array, giving constant-time index lookup. An ordinary unindexed binary heap supplies no such guarantee: locating an arbitrary item can require scanning entries. Item identity and priority must remain distinct, especially when several vertices have equal tentative distances.
The attractive compromise is local organization with global usefulness. A binary heap maintains only the heap order, yet every
extract-min gives the next smallest key. Repeated extraction of the original example gives , so a priority queue also supplies a sorting algorithm without storing a sorted array between extractions. Complete binary tree Created 2026-10-13 Updated 2026-10-14
A complete binary tree is a binary tree whose levels are full except possibly the deepest, which is filled from left to right with no gaps.[ref]
9.1 Binary trees. Data Structures and Algorithms, section 9.1.1: complete shape and binary heap example
Here a level groups vertices by their graph distance from the root of a tree. A binary heap uses this shape to maintain logarithmic height of a binary tree. Completeness differs from the two-children condition of a full binary tree.
Full binary trees, complete binary trees, and perfect binary trees impose different shape conditions
. Each panel states all three properties. Outlined positions expose gaps in the last level. In particular, the five-vertex example in the lower left is both full and complete but is not perfect. Details.For a six-vertex example, give two children in a rooted tree , give two children in a rooted tree , and give only a left child . The levels have vertices, and the last occupies its first three positions, so this is a complete binary tree. It is not a full binary tree, since has exactly one child. Moving to the right slot of preserves and height of a binary tree , but leaves a gap before and destroys completeness. Merely keeping the deepest vertices near the left side is insufficient; every earlier position must be occupied.
Number positions by the left-to-right level order of breadth-first search, beginning with root position . The children of position have positions and . A nonempty complete binary tree occupies exactly positions , so its height of a binary tree is : positions form level . This consecutive occupancy explains the compact array representation of a binary heap, while heap order is a separate condition on values. Neither completeness nor the binary tree definition supplies the binary search tree ordering rule.
Data structure Created 2026-10-13 Updated 2026-10-18
A data structure organizes stored information together with operations for accessing and changing it. Choosing a data structure means choosing which questions should be cheap to answer: an array supports access by numbered position, a hash table supports lookup by key, and a priority queue supports selecting an item by priority. The operations and their time complexity matter as much as the stored values.
Suppose three requests arrive as , where the number is a priority and smaller numbers are more urgent. A FIFO queue removes Ada first because she arrived first. A minimum-oriented priority queue removes Bo first because is the least priority. An array can store the same three records in arrival order, but finding the least priority by scanning this representation takes three key inspections. A binary heap organizes these records so the least priority is immediately available. The information is the same; the representation changes the work needed to use it.
This is a useful design principle: preserve just enough organization for the operations the application needs. Maintaining a sorted array gives the whole order, but moving entries to insert a new key can be expensive. A binary heap keeps a weaker heap order that supports fast repeated selection without maintaining a sorted array. A good data structure makes an algorithm's next step easy.
Heap order Created 2026-10-13 Updated 2026-10-24
The minimum convention for heap order requires every parent in a rooted tree to have priority no greater than each of its children in a rooted tree. The displayed formula uses the array representation of a binary heap. It permits equal priorities and does not require a sorted array; the maximum convention reverses the inequality.
Heapsort 2026-10-31
Build a max-heap in an array, then repeatedly exchange its root with the last element of the active heap and restore heap order by heapify down. The inactive suffix grows in ascending order. Bottom-up heap construction costs because the number of nodes at height decreases geometrically, and the extraction phase costs . Iterative sifting uses constant auxiliary storage. Long-distance exchanges can reverse equal-key records, so the usual version does not provide stable sorting.
Leftist heap 2026-10-20
A binary meldable heap satisfying heap order and the leftist condition: at each node, the shortest path to a missing child is no longer in the right subtree than in the left. Melding recurses down right spines, swaps children when needed, and takes logarithmic time.
Meldable heap Created 2026-10-20 Updated 2026-10-31
A heap data structure supporting a meld operation that combines two heaps into one while preserving the heap order. The cost of melding distinguishes implementations such as a leftist heap from ordinary binary heaps.
For heapsort, use the usual array representation of a max-heap, indexed from zero, with children . Build the max-heap from the last internal node towards the root, using heapify down. The three build stages are
start [2,7,3,2,8,1]
sift at index 2 [2,7,3,2,8,1]
sift at index 1 [2,8,3,2,7,1]
sift at index 0 [8,7,3,2,2,1]At index zero, the value
2 moves below 8 and then below 7. Next exchange the root with the last active element, shorten the active heap, and restore heap order. A vertical separator below distinguishes the active prefix from its sorted final suffix.| Removed maximum | After root exchange | After restoring heap order |
|---|---|---|
1,7,3,2,2 | 8 | 7,2,3,1,2 | 8 | |
2,2,3,1 | 7,8 | 3,2,2,1 | 7,8 | |
1,2,2 | 3,7,8 | 2,1,2 | 3,7,8 | |
2,1 | 2,3,7,8 | 2,1 | 2,3,7,8 | |
1 | 2,2,3,7,8 | 1 | 2,2,3,7,8 |
The trace chooses the left child when equal children tie; other tie conventions can give different intermediate heaps with the same sorted output.
For quicksort, use the head as pivot and partition the remaining elements into those strictly less than it and those greater than or equal to it, retaining their order within each partition. This specifies how the duplicate
2 is handled:pivot 2: [1] | 2 | [7,3,2,8]
pivot 7: [3,2] | 7 | [8]
pivot 3: [2] | 3 | []Empty and singleton lists are already sorted. Returning from the recursive calls gives
Q [3,2] = [2] ++ [3] ++ [] = [2,3]
Q [7,3,2,8] = [2,3] ++ [7] ++ [8] = [2,3,7,8]
Q [2,7,3,2,8,1] = [1] ++ [2] ++ [2,3,7,8]initial: (0,0,0,0,0,0,0,0)
read 2: (0,1,0,0,0,0,0,0)
read 7: (0,1,0,0,0,0,1,0)
read 3: (0,1,1,0,0,0,1,0)
read 2: (0,2,1,0,0,0,1,0)
read 8: (0,2,1,0,0,0,1,1)
read 1: (1,2,1,0,0,0,1,1)The cumulative counts are . For the usual stable sorting version with zero-based output indices, scan the input from right to left, place a key at position , and decrement . The successive placements are
1 at , 8 at , the later 2 at , 3 at , 7 at , and the earlier 2 at . The final answer for all three sorting algorithms isStore the array as a binary heap with min-heap order. Build it bottom-up by sifting down internal nodes in reverse order, rather than inserting all values one at a time. The sum of subtree heights is , so construction costs . Then perform minimum extractions: output the root, move the last remaining entry to the root, and sift it down to restore the heap order.
Each extraction returns the smallest remaining key, so the outputs are the smallest keys in increasing order. For a heap of current size , an extraction takes time. HenceThe tight worst-case bound for this ordinary binary heap implementation isWhen the extraction term is substantial, worst-case extractions follow root-to-leaf paths of logarithmic length; when is small, the linear construction already dominates. The bound stays valid at , since . Building by separate insertions would lose the linear construction bound and is unnecessary.
Store a complete binary tree in an array , with children and parent . The max-heap invariant says every parent's key is at least its children's keys. Consequently the root is a greatest-key item, and the height is .
Here is a pairwise-exchange implementation of
extractMax:extractMax(H, n):
if n == 0: error "empty priority queue"
answer = H[0]
swap(H[0], H[n-1])
n = n - 1
i = 0
while 2*i + 1 < n:
j = 2*i + 1
if j + 1 < n and key(H[j+1]) > key(H[j]):
j = j + 1
if key(H[i]) >= key(H[j]): break
swap(H[i], H[j])
i = j
return (answer, n)Only the root can initially violate heap order. Each heapify down exchange promotes the larger child, making the previous position valid and moving the only possible violation down one level. It either stops at a valid position or reaches a leaf. The removed root is saved as
answer, and reducing the active array length preserves the complete binary tree shape.| Operation | Worst-case time |
|---|---|
Empty initialization, isEmpty, size | |
maximum | |
insert, increaseKey | |
extractMax, deletion by handle | |
| Build from arbitrary items by bottom-up heap construction |
Insertion into the binary heap places an item at the next leaf and moves it upward until heap order holds. Raising a key uses the same upward repair. Arbitrary deletion replaces its position by the final item and repairs upward or downward as necessary. A handle must be updated on exchanges; locating an item by value alone can require linear search. The boxed main bounds are . Dynamic array resizing is usually amortized or avoided by reserving sufficient capacity.
The active prefix of the array must represent a complete -ary tree, filled in the prescribed order, and must obey heap order:Equivalently, every parent is no larger than each existing child. Repeatedly following parents shows that the root contains a global minimum. The array representation already provides the complete-tree shape; it is not enough to check only that the root is a minimum, since the inequality must hold throughout the d-ary min-heap. Assume integral throughout the heap operations.
Save the root, move the last active entry to the root, shrink the active prefix, then restore heap order by heapify down:Only edges descending from the moved entry can violate heap order. If the entry is no larger than every child, the entire heap is valid. Otherwise swapping with a minimum child restores the order at the old position: that child is no larger than the old entry or any sibling. Its original subtree was already ordered, so only the moved entry's new outgoing edges can remain invalid. This is the loop invariant of
ExtractMin(A):
if A.heap_size == 0:
error "empty heap"
answer = A[0]
A[0] = A[A.heap_size-1]
A.heap_size = A.heap_size-1
if A.heap_size > 0:
SiftDown(A,0)
return answer
SiftDown(A,i):
while true:
best = i
for j = 0,...,d-1:
c = Child(i,j)
if c >= A.heap_size:
break
if A[c] < A[best]:
best = c
if best == i:
return
swap A[i], A[best]
i = bestSiftDown. Each swap moves it down one level, proving termination and correctness.For , the height is , and selecting a minimum child costs at most comparisons per level. Thus
ExtractMin takes time, with auxiliary storage. Empty and singleton heaps take constant time. For , there is at most one nonroot level and the loop examines at most actual children, taking ; this also lies within for . The coarser uniform expression safely includes all small sizes.A decreased key can violate heap order only against its parent. An inserted entry begins at the next free position and uses the same repair:Here is a sentinel at least as large as every permitted key. One can equivalently write
DecreaseKey(A,i,key):
if i < 0 or i >= A.heap_size:
error "invalid index"
if key > A[i]:
error "key increased"
A[i] = key
while i > 0:
p = Parent(i)
if A[p] <= A[i]:
return
swap A[p], A[i]
i = p
Insert(A,key):
ensure capacity for A.heap_size+1 entries
i = A.heap_size
A.heap_size = A.heap_size+1
A[i] = +infinity
DecreaseKey(A,i,key)key directly into the new entry and run the upward loop, avoiding any sentinel representation.At every upward swap, the smaller key moves above its larger parent; the displaced parent remains no larger than the entries below it, as follows from the old heap order. Thus only the new parent edge can be invalid. At most one parent comparison is needed per level, with no scan of siblings. Both operations take time in the usual range, or uniformly including tiny heaps and large .
The heap-operation bound assumes space for the inserted entry. A capacity expansion in a dynamic array can cost for that individual insertion; sufficient preallocation avoids it, while geometric capacity growth adds only constant amortized allocation cost per insertion.
Build a max-heap, then repeatedly swap its root with the last element of the active prefix, shrink that prefix and restore heap order by heapify down. A zero-based implementation is
for i = floor(n/2)-1,...,0:
siftDown(A,i,n)
for end = n-1,...,1:
swap A[0],A[end]
siftDown(A,0,end)siftDown(A,i,end) repeatedly exchanges entry i with its larger child while the child lies below end and has a larger key. The suffix beyond end is already sorted and never touched again. For the specified input, key stages of heapsort areLeaves already obey the heap order. Process indices , calling the preceding repair at each. When an index is processed, its descendants have already been processed, so the repair's precondition holds. The resulting array is a max-heap.
The bound obtained by charging to every call is unnecessarily large. The number of nodes with height at least is at most . ThereforeThe total repair work is thus , and the loop itself has a linear number of iterations, giving for this bottom-up heap construction. Most nodes are near the leaves and require little repair.
Store a complete binary tree in a one-indexed array , level by level. Index has parent in a rooted tree for and possible children in a rooted tree and , present only when their indices are at most . The max-heap condition is for every .
Following these inequalities from the root of a tree to any entry proves that is a maximum. The heap order does not sort siblings or unrelated branches. The complete binary tree has height , which bounds how far any single repair can travel. Store the current heap size separately from the array's capacity.
A maximum priority queue stores keyed entries and supports insertion, inspection and removal of an entry with greatest key, and key increases. A max-heap gives the following running times, with the size/capacity cost of the backing array accounted for separately:
maximum: return the root key in time.insert: append at the next available leaf, then use sift up until the heap order holds, in time.extractMaximum: save the root, replace it by the last entry, reduce the size, and use sift down, in time.increaseKey(i,k): reject ; otherwise set the new key and use sift up, in time.isEmptyandsize: inspect the stored size in time; construct a queue from keys by bottom-up heap construction in time.
Given the target's current heap index , remove it as follows. If , discard the last entry. Otherwise replace by and reduce by one. If the replacement is larger than its parent in a rooted tree, use sift up; otherwise use the maximum-oriented sift down from .
Only comparisons incident to the replacement can initially violate the heap order. If it exceeds its parent, it also dominates the old children because the old key dominated those children and was no larger than the parent; an upward repair suffices. Otherwise the upward comparison is valid and only a downward repair can be needed. Thus removal takes worst-case time after the location is known. Searching an unindexed heap for an arbitrary specified key can instead require time; the logarithmic bound does not include such a search.
A minimum-oriented binary heap is an appropriate alternative. Store a complete binary tree in an array and maintain heap order. Insertion appends a value and moves it upward; removing the root replaces it by the last value and moves that value downward. Each path has levels, and equal values can be stored in separate slots. Both operations therefore take time when capacity is available.
Unlike a binary search tree, the heap does not maintain a complete search order, so finding an arbitrary specified value can require inspections. A simple array implementation also has a capacity issue: a fixed array can fill, and resizing a growable array occasionally costs , giving an amortized insertion guarantee unless allocation is otherwise managed. This capacity cost is an implementation tradeoff, not an inherent inability of heaps to represent the priority queue abstraction.
Sift down 2026-10-13
To repair a key in a minimum-oriented binary heap, choose the smaller-priority present entry among its children in a rooted tree. Exchange if that entry is smaller than the moving key, and continue at the new index. Stop when there are no children in a rooted tree or the heap order holds. The smaller rooted trees below the starting entry must already obey the heap order; choosing the larger child could leave a violation with the smaller one.


