WHY array, not pointers? A complete tree has no holes — every level is full except possibly the last, filled left-to-right. That regular shape means we can compute child/parent positions with arithmetic, so we need zero pointers and zero extra memory. This is the secret to "in-place".
Recall Why is
parent = (i-1)/2?
Left child of p is 2p+1, right is 2p+2. Invert both: from 2p+1 we get p=(i−1)/2; from 2p+2 we get p=(i−2)/2. Integer floor division of (i−1)/2 collapses both cases into one formula.
Swap root (max) with last heap slot, shrink heap by one, sift the new root down. Repeat.
The workhorse for both is sift-down (a.k.a. max_heapify).
def sift_down(A, i, n): # heap occupies A[0..n-1] while True: l, r = 2*i + 1, 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 # heap property restored A[i], A[largest] = A[largest], A[i] i = largest # follow the swap downwarddef heap_sort(A): n = len(A) # Phase 1: build max-heap, bottom-up from last parent for i in range(n//2 - 1, -1, -1): sift_down(A, i, n) # Phase 2: extract max repeatedly for end in range(n - 1, 0, -1): A[0], A[end] = A[end], A[0] # biggest -> sorted tail sift_down(A, 0, end) # restore heap of size `end`
Naive guess:n nodes ×logn = O(nlogn). Tighter truth: most nodes are near the bottom and sift-down only a little.
At height h from the bottom there are at most ⌈n/2h+1⌉ nodes, each costing O(h):
Tbuild=∑h=0⌊logn⌋2h+1nO(h)=O(n∑h=0∞2hh).
Now evaluate the series. Let S=∑h≥0hxh=(1−x)2x. At x=21: S=(1/2)21/2=2. Hence
Tbuild=O(2n)=O(n).
At the last internal node, index ⌊n/2⌋−1, going down to 0.
Why is build-heap O(n) not O(nlogn)?
Most nodes are near the bottom; ∑h(n/2h+1)⋅h=O(n) since ∑h/2h=2.
What precondition does sift-down need?
Both subtrees of node i are already valid heaps.
Phase 2 step in one line
Swap root with last heap slot, shrink heap, sift-down new root.
Max-heap vs min-heap for ascending sort?
Use a max-heap; the largest gets parked at the end each round.
Heap stored in array — why no pointers?
It is a complete tree, so child/parent positions are pure index arithmetic.
Recall Feynman: explain to a 12-year-old
Imagine a pile of numbered cards arranged like a pyramid, where the rule is every card is bigger than the two cards below it. So the biggest card is always on top. To sort them: take the top (biggest) card and put it at the very end of your row. Then a small card is now on top breaking the rule, so you let it "sink" down — keep swapping it with the bigger of the two cards beneath until the pyramid rule is fixed again. Now the new top is the next-biggest; park it just before the last one. Repeat until the pyramid is empty — your row is sorted, and you never needed a second table to do it on!
Heap sort ka core idea simple hai: ek max-heap banao, jisme rule hota hai ki har parent apne dono children se bada ya barabar hota hai — isliye sabse bada element hamesha root (index 0) par hota hai. Heap ko hum ek normal array me hi store karte hain, koi pointer nahi chahiye, kyunki tree complete hai aur child/parent ki position sirf index arithmetic se nikal jaati hai (2i+1, 2i+2, ⌊(i−1)/2⌋). Isi wajah se heap sort in-place hai — extra memory O(1).
Algorithm do phase me chalta hai. Phase 1 (build heap): array ke last internal node (n/2−1) se neeche tak sift_down chalao, bottom-up, taaki poora array max-heap ban jaye. Phase 2 (extract): root (sabse bada) ko array ke last slot se swap karo, heap ka size ek kam kar do, aur naye root ko sift_down karke heap property wapas theek karo. Har baar sabse bada element peeche "park" hota jaata hai, aur sorted region right side se badhta jaata hai.
Complexity ka maza yahan hai: ek sift-down O(logn) leta hai, n extractions = O(nlogn). Lekin build-heap sirf O(n) hai, O(nlogn) nahi! Kyunki zyada-tar nodes leaves ke paas hote hain aur thoda hi neeche jaate hain — series ∑h/2h=2 converge hoti hai. Total fir bhi O(nlogn), aur worst case bhi O(nlogn) (quicksort ki tarah O(n2) nahi). Bas yaad rakho: heap sort stable nahi hai, aur ascending sort ke liye max-heap use karna — min-heap se descending milega. Common galti: Phase 2 me sift_down ko full length pass mat karo, shrinking size end do, warna sorted tail kharab ho jaayega.