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.
Consider
The 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 .
Figure 1. . Matching indices identify the same entries in both representations. The heap order compares each parent in a rooted tree with its children in a rooted tree; it does not make a sorted array. Details.
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.
Figure 2.
Sift up inserts 1, then sift down restores the original binary heap after removing 1
. The four panels show the start and end of each repair. Colored arrows mark the moving key's graph path. The extraction panels contain seven entries: index 3 has no children in a rooted tree. Details.
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:
OperationTime complexityReason
peekRead 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 arrayApply 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]
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]
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.
Figure 1. . 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 maximumAfter root exchangeAfter restoring heap order
1,7,3,2,2 | 87,2,3,1,2 | 8
2,2,3,1 | 7,83,2,2,1 | 7,8
1,2,2 | 3,7,82,1,2 | 3,7,8
2,1 | 2,3,7,82,1 | 2,3,7,8
1 | 2,2,3,7,81 | 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]
For counting sort, count keys through . After reading each input key, the count vector is
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 is
Store 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. Hence
The tight worst-case bound for this ordinary binary heap implementation is
When 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.
The binary heap operation costs, with existing positions available for handle operations, are:
OperationWorst-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:
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 = best
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 SiftDown. 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:
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)
Here is a sentinel at least as large as every permitted key. One can equivalently write 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 are
StageActive max heapSorted suffix
Bottom-up heap construction
Extract 5, repair
Extract 4, repair
Extract 3, repair
Extract 2
The final array is . Bottom-up construction takes time because there are progressively fewer nodes at each greater subtree height; the extractions give worst-case time and constant auxiliary storage for iterative sifting.
Leaves 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 . Therefore
The 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:
Empty-queue inspections and removals need an explicit failure result. The index argument to increaseKey must identify the entry's current location: if callers use item handles, update their location records during swaps.
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.