CSE3144 Β· Advanced Data Structures Β· Jul–Nov Semester 2026 Β· Lecture 16 of 36 Β· CO CSE3144.3

Binary Heaps & Heap Operations

Lecture 15 asked "which tree for which job?" Here's a job none of those trees are built for: repeatedly hand over the largest (or smallest) item in a changing collection β€” fast, and without ever fully sorting anything.

Dr. Manu ShrivastavaCourse Instructor Β· Consultation Fri 2–5 PM, LHC 308F
~70 minutesSession outcome: implement heap insertion, deletion, and heapify operations
L16 Β· 00 β€” Agenda ~70 min

Today, part by part

Why binary heaps?

00–05

The priority-queue problem, and why sorted arrays, unsorted arrays, and balanced BSTs all fall short.

Shape property + heap property

05–10

A complete binary tree stored in a plain array β€” no pointers, ever.

Advantages and limitations

10–15

O(log n) insert/extract with nothing but an array β€” at the cost of no arbitrary search and no cheap merge.

The two algorithms: MAX-HEAPIFY and BUILD-MAX-HEAP

15–21

Both in full, plus why the loop starts at ⌊n/2⌋ and counts downwards.

Animation: BUILD-MAX-HEAP, bottom-up

21–36

10 values, 5 heapify calls, every comparison and every swap β€” including the ones that change nothing.

Why BUILD-MAX-HEAP is O(n), not O(n log n)

30–34

The tight analysis, in three lines.

Animation: HEAP-INSERT (sift-up)

34–44

One insertion that bubbles all the way to the root, one that stops immediately.

Animation: HEAP-EXTRACT-MAX (sift-down)

44–53

Pull the root, promote the last leaf, and watch it sink back into place.

Complexity, all operations

53–57

One table, every cost we just verified by hand.

Where heaps actually run

57–62

Huffman coding, external-sort run generation, and a look ahead to Dijkstra/Prim.

Recap & what's next

62–70

Lecture 17: Heap Sort and Priority Queue Applications.

CSE3144 β€” Lecture 16
L16 Β· 01 β€” Why binary heaps? ~5 min

The priority-queue problem: always hand over the extreme element, fast

The problem

A collection keeps changing β€” items are added, and repeatedly you need to pull out the current maximum (or minimum), never a specific key, never the full sorted order. Job schedulers, event simulators, and Lecture 6's Huffman-code builder all have exactly this shape: "give me the most/least urgent item right now."

Why the obvious answers fall short
  • Unsorted array: insert is O(1), but finding the max means scanning everything β€” O(n) every single extraction.
  • Sorted array: extracting the max is O(1) (just take the end), but inserting means shifting elements to keep it sorted β€” O(n) every insertion.
  • Balanced BST (Lecture 7–9): O(log n) for both β€” but it's a much bigger hammer than this job needs: pointers, rotations, and full ordering support you never asked for, just to repeatedly find an extreme value.
The heap's answer

A binary heap gives O(log n) insert and O(log n) extract-max, matching the balanced BST β€” but needs nothing more than a plain array, no pointers, no rotation cases to get wrong, and can be built from an unsorted array in O(n), faster than inserting n elements one at a time.

CSE3144 β€” Lecture 16 Β· Why binary heaps
L16 Β· 02 β€” Shape + heap property ~5 min

A complete binary tree, obeying one ordering rule, stored as a plain array

Two properties, together
  • Shape property: the tree is a complete binary tree β€” every level is completely filled except possibly the last, which fills left to right with no gaps.
  • Max-heap property: for every node i (except the root), A[PARENT(i)] ≥ A[i]. The maximum is always at the root.
  • Min-heap property (the mirror image): A[PARENT(i)] ≤ A[i] everywhere β€” the minimum is always at the root. Everything today works identically for min-heaps; we'll build max-heaps throughout.
The array trick β€” no pointers, ever

Because the shape is always a complete tree, position alone determines structure. Store the tree in an array A, 1-indexed, level by level, left to right:

PARENT(i) = ⌊i/2⌋    LEFT(i) = 2i    RIGHT(i) = 2i+1

Every animation today shows the array and the tree side by side β€” they are the same object, just two views of it.

CSE3144 β€” Lecture 16 Β· Shape & heap property
L16 Β· 03 β€” Advantages & limitations ~5 min

Exactly the right tool for "give me the extreme one" β€” and nothing more

Advantages
  • O(1) peek at the max (or min) β€” it's always the root.
  • O(log n) insert and O(log n) extract-max β€” matching a balanced BST with far simpler code.
  • O(n) build from an arbitrary array β€” a genuinely surprising tight bound we'll prove today, not the loose O(n log n) you'd guess from "n calls, each O(log n)."
  • Pure array storage β€” no pointers, no per-node overhead, excellent cache locality.
Limitations
  • No efficient arbitrary search. The heap property only relates a node to its parent β€” it says nothing about left vs. right siblings or across subtrees. Finding "is key 7 in this heap?" is O(n), not O(log n).
  • No efficient decrease-key/increase-key without an auxiliary index map to locate a given key inside the array first. This exact limitation is what motivates Fibonacci heaps (Lecture 19) for algorithms like Dijkstra's shortest path that decrease-key constantly.
  • No efficient merge of two heaps β€” combining two binary heaps means an O(n) rebuild. This motivates Binomial and Pairing heaps (Lectures 18 and 20), built specifically to merge quickly.
  • Heap order ≠ sorted order. Reading the array top to bottom does not give you sorted output β€” that takes repeated extraction, which is exactly what Lecture 17's Heap Sort does.
CSE3144 β€” Lecture 16 Β· Advantages & limitations
L16 Β· 03a β€” The two algorithms ~6 min

One helper does all the work; the builder just calls it n/2 times

Everything in the next animation is these two procedures. Arrays are 1-indexed, so for node i the children are 2i and 2i+1 and the parent is ⌊i/2⌋ β€” no pointers anywhere, just arithmetic on indices.

MAX-HEAPIFY(A, i) β€” push one bad value down
MAX-HEAPIFY(A, i, n):
    l = 2i          // left child
    r = 2i + 1      // right child
    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:
        swap A[i] ↔ A[largest]
        MAX-HEAPIFY(A, largest, n)

The precondition matters: the subtrees rooted at 2i and 2i+1 must already be valid heaps. Only A[i] may be out of place. The job is to float that one value down to where it belongs β€” and the final recursive call is exactly that: having swapped it one level down, follow it and check again.

BUILD-MAX-HEAP(A) β€” fix the whole array
BUILD-MAX-HEAP(A, n):
    for i = ⌊n/2⌋ downto 1:
        MAX-HEAPIFY(A, i, n)

That's the entire algorithm β€” three lines. Two questions it immediately raises, and both are answered by the precondition above:

  • Why start at ⌊n/2⌋? Every index past ⌊n/2⌋ is a leaf, and a lone node is already a valid heap. For n = 10 that means indices 6…10 are skipped outright β€” half the array, for free.
  • Why count downwards? MAX-HEAPIFY(A, i) is only allowed to run once i's children are already heaps. Going bottom-up guarantees exactly that: by the time you reach i, everything beneath it has been fixed.
Trace one call by hand before watching it

Take the array from the next slide, A = [4, 1, 3, 2, 16, 9, 10, 14, 8, 7], and run the very first call, MAX-HEAPIFY(A, 5):

  • i = 5, so l = 10, r = 11. A[5] = 16.
  • l = 10 ≤ 10 and A[10] = 7 > 16? No β€” largest stays 5.
  • r = 11 ≤ 10? No, past the end β€” skipped.
  • largest = i, so no swap, no recursion. 16 was already bigger than its only child.

That "nothing happened" case is a real step in the animation, not a skipped one β€” it is exactly what the if largest ≠ i test is there to detect.

What each one costs

MAX-HEAPIFY follows one root-to-leaf path in the worst case, doing a constant amount of work per level → O(log n).

BUILD-MAX-HEAP makes n/2 such calls, so the obvious bound is O(n log n) β€” but that is loose. Most of those calls are on short subtrees near the bottom, and the true total is O(n). L16Β·05 does that summation properly; for now, just notice while watching that the early calls barely move anything, and only the last few travel far.

CSE3144 β€” Lecture 16 Β· The algorithms
L16 Β· 04 β€” Animation: BUILD-MAX-HEAP ~15 min

Turn an arbitrary array into a max-heap, bottom-up

Classic array A = [4, 1, 3, 2, 16, 9, 10, 14, 8, 7] (10 elements). BUILD-MAX-HEAP calls MAX-HEAPIFY on every node from index ⌊n/2⌋=5 down to index 1 β€” skipping the leaves entirely, since a single node is trivially a valid heap. Every comparison, every swap, and every "no change needed" moment is shown, in both the array and the tree view.

Interactive β€” BUILD-MAX-HEAP(A), i = 5 down to 1
CSE3144 β€” Lecture 16 Β· BUILD-MAX-HEAP
L16 Β· 05 β€” Why BUILD-MAX-HEAP is O(n) ~4 min

The loose bound says O(n log n). The tight bound says O(n).

The loose (wrong) argument

"n calls to MAX-HEAPIFY, each costing O(log n)" gives O(n log n). This is a valid upper bound β€” but it's not tight, because it assumes every node sits near the top of the tree, costing a full O(log n). Most nodes don't.

The tight argument

MAX-HEAPIFY on a node of height h costs O(h) β€” and a heap of n nodes has at most ⌈n/2h+1⌉ nodes at height h. So total cost is bounded by:

h=0lg n ⌈n/2h+1⌉ · O(h)  =  O(n · ∑h=0lg n h/2h)  =  O(n)

The sum ∑ h/2h converges to a constant (2) regardless of n β€” most nodes are near the bottom (cheap, O(1)-ish), and only a few are near the top (expensive, O(log n)), and that trade-off exactly cancels out to linear total work.

The same formula, with actual numbers β€” the n = 10 heap from L16Β·04

First, what "height" means here. It is counted upward from the bottom, not downward from the root: a leaf has h = 0, its parent h = 1, and the root has the largest height of all. (Depth is the other one β€” that counts down from the root.) That is why the exponent is h+1: at h = 0 the formula gives ⌈n/2⌉, i.e. half the nodes are leaves β€” exactly right for a complete tree.

height hwhich nodesactualbound ⌈n/2h+1
0 (leaves)6, 7, 8, 9, 105⌈10/2⌉ = 5
13, 4, 53⌈10/4⌉ = 3
221⌈10/8⌉ = 2
31 (root)1⌈10/16⌉ = 1

The counts total 10, and the heap's own height is 3 = ⌊lg 10⌋. Notice h = 2: the bound says "at most 2" while the truth is 1 β€” it is only an upper bound, which is all the proof needs.

And this is the whole reason the answer is O(n). The most numerous class is h = 0 β€” about half of every heap β€” and it costs O(0). BUILD-MAX-HEAP does not even call those: the loop stops at ⌊n/2⌋ = 5, so nodes 6…10 are skipped outright. Meanwhile the expensive class, h = lg n, costs O(log n) but contains exactly one node. Every time the cost goes up by one, the population halves β€” and it is that skew, not the per-call cost, that collapses the total to linear.

CSE3144 β€” Lecture 16 Β· Tight analysis of BUILD-MAX-HEAP
L16 Β· 06 β€” Animation: HEAP-INSERT (sift-up) ~10 min

Append at the end, then bubble up until the heap property is restored

Two insertions into the heap we just built: 17, which bubbles all the way from a leaf to the new root (the worst case), and 5, which settles in a single comparison (the best case). Both are shown in full β€” including the comparison that causes zero swaps.

Interactive β€” insert 17, then insert 5
CSE3144 β€” Lecture 16 Β· HEAP-INSERT
L16 Β· 07 β€” Animation: HEAP-EXTRACT-MAX (sift-down) ~9 min

Take the root, promote the last leaf, then sink it back into place

Extracting the maximum from the 12-element heap built by the last two insertions. The root (17) is removed and returned; the last element takes its place (keeping the shape property intact); then MAX-HEAPIFY sinks it down until the heap property holds again β€” three full levels, every comparison shown.

Interactive β€” HEAP-EXTRACT-MAX(A)
CSE3144 β€” Lecture 16 Β· HEAP-EXTRACT-MAX
L16 Β· 08 β€” Complexity, all operations ~4 min

Everything we just verified by hand, in one table

OperationCostVerified today as
PEEK-MAX / PEEK-MINO(1)always the root, A[1]
MAX-HEAPIFY (sift-down from height h)O(h) = O(log n) worst caseup to 3 comparisons in a 12-node heap
HEAP-INSERT (sift-up)O(log n) worst case3 swaps for insert(17); 0 swaps for insert(5)
HEAP-EXTRACT-MAX (sift-down)O(log n) worst case3 swaps to restore a 12-node heap
BUILD-MAX-HEAPO(n) tight bound (not O(n log n))7 total swaps across 5 heapify calls on 10 elements

n = number of elements currently in the heap; h = height of the node being sifted, which is at most ⌊log₂n⌋.

CSE3144 β€” Lecture 16 Β· Complexity
L16 Β· 09 β€” Where heaps actually run ~5 min

Not a hypothetical exercise β€” you've already used one

Huffman coding β€” Lecture 6

The classic Huffman algorithm repeatedly extracts the two lowest-frequency nodes and reinserts their merged parent β€” exactly the extract-min / insert cycle we animated today, run nβˆ’1 times, backed by a min-priority queue.

External sorting β€” Lecture 5

Lecture 5's tournament trees solved the same underlying problem β€” repeatedly identify the current minimum across many runs β€” for merge and replacement selection. A binary heap is the in-memory, array-based cousin of that same repeated-extract-min idea.

Heap sort β€” next lecture

BUILD-MAX-HEAP once, then repeatedly swap the root with the last element and MAX-HEAPIFY the shrinking heap β€” an in-place O(n log n) sort using nothing we haven't already built today. Full treatment in Lecture 17.

Job / event scheduling

Operating-system schedulers and discrete-event simulators use a priority queue keyed on deadline or timestamp β€” "run the most urgent job next" is the priority-queue problem, verbatim.

Graph algorithms (general CS knowledge)

Dijkstra's shortest-path and Prim's minimum-spanning-tree algorithms both repeatedly pick the cheapest available edge/vertex β€” the standard implementation uses a binary heap as the priority queue, upgraded to a Fibonacci heap (Lecture 19) when decrease-key dominates.

Median / order-statistics maintenance

A pair of heaps (one max-heap for the lower half, one min-heap for the upper half) maintains a running median in O(log n) per insertion β€” a common interview and streaming-data pattern.

CSE3144 β€” Lecture 16 Β· Real-world use
L16 Β· 10 β€” Recap & what's next ~8 min

One array, two properties, three operations β€” all O(log n) or better

Lecture 17 β€” next

Heap Sort and Priority Queue Applications

Turn today's BUILD-MAX-HEAP and MAX-HEAPIFY into an in-place O(n log n) sort, then apply priority queues to scheduling problems.

Homework β€” bring to Lecture 17
  • Run BUILD-MAX-HEAP by hand on A = [1, 7, 3, 12, 5, 9, 2, 15, 8]. Show every MAX-HEAPIFY call and count total swaps.
  • Starting from your heap above, insert 20 and then insert 4. Which one bubbles further, and why?
  • From the heap after both insertions, run HEAP-EXTRACT-MAX twice in a row. Show the array after each extraction.
  • In 3–4 sentences: why can't you binary-search a max-heap's array to check whether a given key is present? What property would you need that a heap doesn't guarantee?
CSE3144 β€” Lecture 16

Questions?

Dr. Manu Shrivastava β€” LHC 308F β€” Friday 2:00–5:00 PM

Next: Lecture 17 β€” Heap Sort and Priority Queue Applications.