Algorithm Search⌘K

Proofs: Postorder traversal

These are the human proofs of Postorder traversal, at full length.

The stack-based postorder traversal lists the tree in postorder full

This proof shows: correctness, termination.

Let TT be an ordered tree rooted at rr, with child lists C[v]C[v], and let post(Tv)\mathrm{post}(T_v) be the postorder of the subtree of vv: post(Tv)=post(Tc1),…,post(Tck),v\mathrm{post}(T_v) = \mathrm{post}(T_{c_1}), \ldots, \mathrm{post}(T_{c_k}), v for C[v]=[c1,…,ck]C[v] = [c_1, \ldots, c_k]. One step is one run of the body of the loop (lines L4 to L10).

Claim. Suppose that at some moment the stack is S0S_0 followed by (v,0)(v, 0) on top, and out is XX. Then after exactly 2∣Tv∣−12|T_v| - 1 more steps, the stack is S0S_0 and out is X,post(Tv)X, \mathrm{post}(T_v). During these steps no pair of S0S_0 is read or changed.

Proof. By strong induction on the height of vv. Let C[v]=[c1,…,ck]C[v] = [c_1, \ldots, c_k].

Base, k=0k = 0. The next step reads (v,0)(v, 0) at line L4. The test 0<00 < 0 of line L5 fails, so lines L9 and L10 pop the pair and append vv. One step was used, 2⋅1−1=12 \cdot 1 - 1 = 1, and out is X,v=X,post(Tv)X, v = X, \mathrm{post}(T_v).

Step, k≥1k \ge 1. Each child has a smaller height, so the claim holds for it. By an inner induction on j=0,…,kj = 0, \ldots, k: after ∑l≤j2∣Tcl∣\sum_{l \le j} 2|T_{c_l}| steps, the stack is S0,(v,j)S_0, (v, j) and out is X,post(Tc1),…,post(Tcj)X, \mathrm{post}(T_{c_1}), \ldots, \mathrm{post}(T_{c_j}). This holds for j=0j = 0. For j<kj < k, the next step reads (v,j)(v, j), finds j<kj < k, changes the pair to (v,j+1)(v, j + 1) and pushes (cj+1,0)(c_{j+1}, 0) at lines L6 and L7. It appends nothing. By the claim for cj+1c_{j+1}, after 2∣Tcj+1∣−12|T_{c_{j+1}}| - 1 more steps the stack is S0,(v,j+1)S_0, (v, j + 1) and out has grown by post(Tcj+1)\mathrm{post}(T_{c_{j+1}}), and the pairs below (cj+1,0)(c_{j+1}, 0) were not touched. That is 2∣Tcj+1∣2|T_{c_{j+1}}| steps in all, which proves the inner step.

At j=kj = k the next step finds k=∣C[v]∣k = |C[v]|, pops (v,k)(v, k) and appends vv. So out is X,post(Tc1),…,post(Tck),v=X,post(Tv)X, \mathrm{post}(T_{c_1}), \ldots, \mathrm{post}(T_{c_k}), v = X, \mathrm{post}(T_v), and the stack is S0S_0. The number of steps is ∑l=1k2∣Tcl∣+1=2(∣Tv∣−1)+1=2∣Tv∣−1\sum_{l=1}^{k} 2|T_{c_l}| + 1 = 2(|T_v| - 1) + 1 = 2|T_v| - 1, because the subtrees of the children partition the vertices of TvT_v other than vv. Only the pair of vv and the pairs above it were read or changed. □\square

Theorem. POSTORDER(C,r)(C, r) stops after 2n−12n - 1 steps and returns post(Tr)\mathrm{post}(T_r).

Proof. After lines L1 and L2, out is empty and the stack is the empty stack followed by (r,0)(r, 0). By the claim with XX empty, after 2n−12n - 1 steps the stack is empty and out is post(Tr)\mathrm{post}(T_r). The test of line L3 then fails, and line L11 returns out. The number of steps is finite, so the procedure terminates. ■\blacksquare

Stack size. By the claim, the pairs on the stack are always the vertices of one path that starts at rr and goes down. So the stack holds at most h+1h + 1 pairs, where hh is the height of TT.

Back to Postorder traversal