3.4.11Trees

Heapify — bottom-up O(n) build

2,113 words10 min readdifficulty · medium

WHAT is heapify?

Array ↔ tree index map (0-based):

  • parent of ii: (i1)/2\lfloor (i-1)/2 \rfloor
  • left child of ii: 2i+12i+1
  • right child of ii: 2i+22i+2
  • last internal (non-leaf) node: index n/21\lfloor n/2 \rfloor - 1 (everything after it is a leaf).

HOW: the siftDown operation

siftDown(i) assumes the subtrees rooted at i's children are already valid heaps, and pushes A[i] down until the heap property holds.

siftDown(A, i, n):
    while True:
        l = 2*i + 1
        r = 2*i + 2
        largest = i
        if l < n and A[l] > A[largest]: largest = l
        if r < n and A[r] > A[largest]: largest = r
        if largest == i: break          # parent already biggest
        swap(A[i], A[largest])
        i = largest                     # follow the swap down
buildHeap(A, n):
    for i from floor(n/2)-1 down to 0:
        siftDown(A, i, n)
Figure — Heapify — bottom-up O(n) build

DERIVATION: why is it O(n)O(n) and not O(nlogn)O(n\log n)?

Set-up. A complete binary tree of nn nodes has height h=log2nh = \lfloor \log_2 n \rfloor. Measure node height from the bottom: leaves have height 00, root has height hh.

Cost of one siftDown. A node at height kk can sink at most kk levels, so its work is O(k)O(k).

Count nodes at each height. In a (near-)complete tree there are at most n/2k+1\lceil n / 2^{k+1}\rceil nodes at height kk.

Sum the total work.

T(n)  =  k=0hn2k+1countO(k)cost  =  O ⁣(nk=0hk2k+1)    O ⁣(n2k=0k2k).T(n) \;=\; \sum_{k=0}^{h} \underbrace{\frac{n}{2^{k+1}}}_{\text{count}} \cdot \underbrace{O(k)}_{\text{cost}} \;=\; O\!\left(n \sum_{k=0}^{h} \frac{k}{2^{k+1}}\right) \;\le\; O\!\left(\frac{n}{2}\sum_{k=0}^{\infty} \frac{k}{2^{k}}\right).

Now evaluate the key infinite sum. Use the standard identity (derived below):

k=0kxk  =  x(1x)2,x<1.\sum_{k=0}^{\infty} k\,x^{k} \;=\; \frac{x}{(1-x)^2}, \qquad |x|<1.

Plug x=12x = \tfrac12:

k=0k2k=1/2(11/2)2=1/21/4=2.\sum_{k=0}^{\infty} \frac{k}{2^{k}} = \frac{1/2}{(1-1/2)^2} = \frac{1/2}{1/4} = 2.

Therefore

T(n)O ⁣(n22)=O(n).T(n) \le O\!\left(\frac{n}{2}\cdot 2\right) = \boxed{O(n)}.

Worked examples


Common mistakes


Recall Feynman: explain to a 12-year-old

Imagine a tournament bracket drawn as a pyramid of people, biggest-and-strongest should be on top. Most people stand at the bottom rows — there are tons of them, but each only has to wrestle one or two people right above them: cheap. As you go up, there are way fewer people, and only those few have long climbs. Because the crowded bottom is cheap and the tall climbs are rare, the total wrestling is just "about one match per person" — it grows in a straight line with the number of people, not faster.


Flashcards

What is the time complexity of bottom-up heapify?
O(n)O(n) (linear), tighter than the loose O(nlogn)O(n\log n) bound.
At which index does bottom-up build-heap start?
The last internal node, n/21\lfloor n/2\rfloor - 1 (everything after is a leaf).
Why do we process nodes from bottom to top in build-heap?
siftDown(i) requires both children's subtrees to already be valid heaps; bottom-up guarantees that ordering.
Cost of siftDown on a node at height kk?
O(k)O(k) — it can sink at most kk levels.
How many nodes are at height kk (at most)?
About n/2k+1n/2^{k+1}; tall nodes are exponentially rare.
Which infinite sum proves the O(n)O(n) bound, and its value?
k=0k/2k=2\sum_{k=0}^{\infty} k/2^{k} = 2, a constant.
Derive kxk\sum k x^k.
Differentiate xk=1/(1x)\sum x^k = 1/(1-x) to get kxk1=1/(1x)2\sum k x^{k-1}=1/(1-x)^2, then multiply by xx: kxk=x/(1x)2\sum k x^k = x/(1-x)^2.
Why is insertion-based build O(nlogn)O(n\log n) but siftDown build O(n)O(n)?
siftUp moves the numerous leaves toward the root (expensive direction); siftDown gives the long path only to rare tall nodes.
Children/parent index formulas (0-based)?
left =2i+1=2i+1, right =2i+2=2i+2, parent =(i1)/2=\lfloor(i-1)/2\rfloor.
Why are leaves skipped?
A single node is already a valid heap; sifting it is wasted work and risks out-of-bounds child access.

Connections

  • Binary Heap — the data structure heapify produces.
  • Heapsort — uses build-heap (O(n)O(n)) then nn extract-max (O(nlogn)O(n\log n)).
  • Priority Queue — heaps as its standard implementation.
  • Complete Binary Tree — the array↔tree index mapping.
  • Geometric Series / Amortized Analysis — the summation trick behind the linear bound.
  • siftUp vs siftDown — why direction decides complexity.

Concept Map

index map defines

calls

begins at

skip so start at

iterates

ensures children heaps first

cost bounded by

few nodes are tall

weighted sum

converges to

beats

restores

Array as complete binary tree

Heap property parent >= children

buildHeap bottom-up

siftDown node

Start at last internal node

Process nodes upward

Leaves already valid

Node height k

Count n over 2^k+1 nodes

Sum k times n over 2^k+1

Total O n

Naive insert O n log n

Hinglish (regional understanding)

Intuition Hinglish mein samjho

Dekho, heap ek aisa array hai jise hum mentally ek complete binary tree maan lete hain — parent index i ke children 2i+1 aur 2i+2 par. Ab agar humein random array ko valid heap banana hai, to ek naive tareeka hai: ek-ek element insert karo aur upar sift karo — yeh O(nlogn)O(n\log n) padta hai. Lekin smart tareeka hai bottom-up heapify: tree ke neeche se shuru karo (index n/21\lfloor n/2\rfloor - 1 se, kyunki uske aage sab leaves hain jo pehle se valid heap hain) aur har node par siftDown karo, root tak upar jaate hue.

siftDown(i) ka kaam simple hai: maan lo i ke dono children ke subtrees already valid heap hain; bas A[i] ko neeche tab tak girao jab tak woh apne sabse bade child se bada na ho jaye (max-heap me). Hum upar ki taraf isliye chalte hain kyunki siftDown ko children ke subtrees pehle se theek chahiye — yeh ek mini dynamic-programming order hai: chhote subtrees pehle solve, fir bade.

Asli magic complexity me hai. Logon ko lagta hai nn nodes × O(logn)O(\log n) = O(nlogn)O(n\log n). Par yeh bound dheela (loose) hai. Sachchai: height kk wale node ka cost sirf O(k)O(k) hai, aur tree me height kk par lagbhag n/2k+1n/2^{k+1} nodes hote hain — yaani tall nodes bahut kam hote hain. Total cost banta hai n2k/2k\frac{n}{2}\sum k/2^k, aur woh sum exactly 2 par converge ho jaata hai (constant). Isliye total O(n)O(n) — bilkul linear! Yaad rakho: "leaves lazy hain, root mehnat karta hai" — neeche bahut nodes par kaam sasta, upar mehnga kaam sirf gine-chune nodes par. Heapsort isi O(n)O(n) build par khada hai, isliye yeh interview aur real systems dono me important hai.

Go deeper — visual, from zero

Test yourself — Trees

Connections