Building a Heap in Linear Time
Naive Build:
Inserting elements one by one, each costing , gives total. This is the obvious approach but not optimal.
Linear-Time Build: Bottom-Up Heapify
A more efficient method calls Max-Heapify on all non-leaf nodes, working bottom-up from down to 1:
Build-Max-Heap(A):
A.heap_size = A.length
for i = floor(A.length / 2) downto 1:
Max-Heapify(A, i)
The key insight: leaves (indices to ) are already 1-element max-heaps, so they need no work. Starting from the last non-leaf node and working upward ensures that when Max-Heapify is called on node , both subtrees of are already valid heaps.
Correctness
Loop invariant: At the start of each iteration, every node index is the root of a valid max-heap.
- Initialisation (): All nodes are leaves, trivially heaps.
- Maintenance: Max-Heapify fixes node ; after the call, is also a heap root. Moving to preserves the invariant.
- Termination (): All nodes, including the root (index 1), are valid heaps.
Analysis: Why
The cost of Max-Heapify at node is proportional to the height of node , i.e. the number of levels below it. At level from the bottom (height ), there are at most nodes, and each Max-Heapify costs . Summing over all levels:
The infinite sum converges: . Therefore:
Concrete Calculation
For (a perfect heap), the tree has 4 levels:
| Level (from leaf) | Height | Nodes at this level | Work per node | Total work |
|---|---|---|---|---|
| 0 (leaves) | 0 | 8 | 0 | 0 |
| 1 | 1 | 4 | ||
| 2 | 2 | 2 | ||
| 3 (root) | 3 | 1 |
Total: , whilst would be . The linear-time build is substantially faster.
Step-by-Step Example
Input: ()
First non-leaf: , value .
Initial array as tree: After Build-Heap (final):
4 16
/ \ / \
1 3 14 10
/ \ / \ / \ / \
2 16 9 10 8 7 9 3
/ \ / / \ /
14 8 7 2 4 1
| Step | Action | Key effect | |
|---|---|---|---|
| 1 | 5 | Max-Heapify on node with value 16 | Already a heap (16 > 7) |
| 2 | 4 | Max-Heapify on node with value 2 | Swap 2 with 14; heap |
| 3 | 3 | Max-Heapify on node with value 3 | Swap 3 with 10; heap |
| 4 | 2 | Max-Heapify on node with value 1 | Swap 1 with 16, then 1 with 7; heap |
| 5 | 1 | Max-Heapify on node with value 4 | Swap 4 with 16, then 4 with 14, then 4 with 8 |
Final heap: .
Summary
| Aspect | Detail |
|---|---|
| Naive build | Insert elements: |
| Efficient build | Bottom-up heapify: |
| Starting index | (last non-leaf) |
| Why | Most nodes (leaves) cost ; higher nodes are few |
| Series sum | converges to 2 |
| Key insight | Work is proportional to height, not depth |