Heaps & heapsort
◈ 6 cardsThe array-as-tree heap, MAX-HEAPIFY in O(lg n), the surprising O(n) build, and an in-place O(n lg n) sort.
A tree that lives in an array
A (binary max-)heap is an array that we read as a nearly-complete binary tree. No pointers: the shape is encoded by arithmetic on indices. Using 1-based CLRS indexing, for node :
- parent is at ,
- left child at , right child at .
The max-heap property is the single local rule for every non-root . It says nothing about siblings — only parent-vs-child. Its one powerful consequence: the largest element is always at the root . Because the tree is nearly complete, its height is , so any root-to-leaf walk does work.
MAX-HEAPIFY — sink one bad node
MAX-HEAPIFY(A, i) assumes the subtrees rooted at 's children are already heaps but may be too small. It finds the largest of , , ; if a child wins, it swaps and recurses into that child — the small value floats down at most levels. The recurrence is (a child holds at most nodes when the bottom level is half full), which the master theorem solves to .
BUILD-MAX-HEAP — and why it is , not
Call MAX-HEAPIFY bottom-up, from the last internal node down to 1. The leaves are already size-1 heaps, so we skip them; going downward guarantees both children are heaps before we fix a node. The loose bound is calls — but it is not tight. Most nodes sit near the leaves, where MAX-HEAPIFY is cheap. There are at most nodes of height , and MAX-HEAPIFY costs on a height- node, so the total is
using at . Building a heap is linear.
Worked example — HEAPSORT
Heapsort has two phases. (1) BUILD-MAX-HEAP puts the max at in . (2) For from downto : swap (the max takes its final sorted slot), shrink the heap by one, and MAX-HEAPIFY the new root. Each of the sift-downs is , so heapsort is in every case, and it is in-place ( extra). It is not stable.
Trace BUILD-MAX-HEAP on (1-based): start at index 5, work down, and cascading sift-downs yield the heap . The runnable exercises reproduce exactly this.