Trees and Graphs
Heaps and priority queues
Always reach the smallest thing fast
A complete tree that secretly lives in a flat array - giving you the smallest item on demand, and the arithmetic that makes pointers unnecessary.
Every scheduler, every shortest-path finder, every "give me the top 10" query has the same nagging need: repeatedly pull the smallest (or largest) thing out of a changing pile - fast. A sorted list makes that pull cheap but every insert expensive. A binary heap strikes the perfect bargain: to add, to remove the minimum, and to peek at it - all inside a plain flat array with no pointers at all.
The idea in one line
A complete tree that hides in an array
Because the tree is complete, we never need pointers to wire nodes together. Just write the tree out level by level into an array, and the structure is encoded purely by index arithmetic. For the node stored at index :
That is the whole trick. "Go to my child" is a multiply-and-add; "go to my parent" is a subtract-and-halve. No allocation, no dereferencing - the array is the tree, and cache-friendly to boot. The heap property () is only a partial order: siblings have no defined relationship, which is exactly why a heap is cheaper to maintain than a fully sorted array.
See it: tree and array, sift up and sift down
Insert a value and watch it drop into the next free array slot, then sift up - swapping with its parent while it is smaller - in the tree and the array at once. Extract-min removes the root, drops the last element into its place, and sifts down. Click any node or cell to reveal its live / index math.
Tree position i is exactly array index i - that correspondence is what makes children live at 2i+1 and 2i+2.
Click any node or array cell to reveal its parent/child index math. Insert a value to watch it sift up; extract-min to watch it sift down.
Why both operations are O(log n)
A complete tree of nodes has height
Sift-up walks from a leaf toward the root; sift-down walks from the root toward a leaf. Either way you touch at most one node per level, doing a single compare-and-swap each time. So insert and extract-min each cost about swaps - while peek is a single array read, , because the minimum never leaves index 0.
Insert and extract-min in code
The entire data structure is one array plus two helpers. Notice there is not a single pointer or node object - every "move" is index arithmetic.
class MinHeap:
def __init__(self):
self.a = [] # the backing array
def push(self, x):
self.a.append(x) # land in the next free slot
self._sift_up(len(self.a) - 1)
def pop_min(self):
top = self.a[0] # the minimum - O(1) to read
last = self.a.pop()
if self.a:
self.a[0] = last # move last element to the root
self._sift_down(0)
return top
def _sift_up(self, i):
while i > 0:
parent = (i - 1) // 2 # parent index
if self.a[i] >= self.a[parent]:
break # heap property holds
self.a[i], self.a[parent] = self.a[parent], self.a[i]
i = parent
def _sift_down(self, i):
n = len(self.a)
while True:
l, r, small = 2*i + 1, 2*i + 2, i # children indices
if l < n and self.a[l] < self.a[small]: small = l
if r < n and self.a[r] < self.a[small]: small = r
if small == i:
break
self.a[i], self.a[small] = self.a[small], self.a[i]
i = smallIn real Python you would just reach for the standard library - import heapq gives you heappush and heappop over an ordinary list, implementing exactly this. Building it once by hand is what makes that black box transparent.
Where heaps quietly run the world
A heap is not sorted
Check yourself
In an array-backed heap, the parent of the node at index i sits at index:
In a min-heap, where does the smallest element always live, giving O(1) peek?
Recall: why are insert and extract-min both O(log n), yet peek is only O(1)?
Tie the height of a complete tree to the cost of each operation. Try to state it, then check.
Lock it in
- A min-heap is a complete binary tree with one rule: every parent is at most its children, so the global minimum sits at the root.
- The tree lives in a flat array by pure index arithmetic: children at 2i+1 and 2i+2, parent at floor((i-1)/2). No pointers, cache-friendly.
- Insert sifts up, extract-min sifts down; both touch one node per level, so both are O(log n) while peek is O(1).
- A heap is only partially ordered: index 0 is the minimum, but the array is not sorted and cannot be binary-searched.
Primary source
Ask your teacher