Algorithm Search⌘K

Proofs: Rooted tree representation (left-child right-sibling)

These are the human proofs of Rooted tree representation (left-child right-sibling), at full length.

The left-child, right-sibling operations keep the invariant, and PREORDER visits the subtree in preorder full

This proof shows: correctness, termination.

Claim. If (T1) to (T4) hold for all nodes before an operation, then: NEW-NODE, ADD-CHILD (with yy a root and xx not in the subtree of yy) and DETACH keep them, and change the trees as the tree type says; CHILDREN(x)(x) visits the children of xx from left to right; and PREORDER(r)(r) visits each node of the subtree of rr exactly once, in preorder, stops, and makes at most 2(m−1)2(m - 1) pointer moves, where mm is the size of the subtree.

Setup. The preorder of the subtree of vv, with children c1,…,cdc_1, \dots, c_d, is pre(v)=(v,pre(c1),…,pre(cd))\mathrm{pre}(v) = (v, \mathrm{pre}(c_1), \dots, \mathrm{pre}(c_d)). The invariant is (T1) to (T4) of the page: the child list of xx starts at x.left-childx.\text{left-child}, follows right-sibling pointers through the children in order and ends with nil, each child points to xx with pp, and a root has nil in pp and right-sibling.

Lemma 1 (ADD-CHILD). Let xx have children c1,…,cdc_1, \dots, c_d. After lines L2 to L4, x.left-child=yx.\text{left-child} = y, y.right-sibling=c1y.\text{right-sibling} = c_1 (nil when d=0d = 0), and y.p=xy.p = x. So the child list of xx is y,c1,…,cdy, c_1, \dots, c_d, which gives (T1) to (T3) for xx. The only fields written are two fields of yy and one of xx. Before the call, yy was a root, so it was in no child list, and by (T4) its two written fields were nil; the child lists of all other nodes are unchanged. Since xx is not in the subtree of yy, the new edge from xx to yy closes no cycle, so the result is again a forest, in which the tree of xx now contains the subtree of yy as the leftmost subtree of xx. □\square

Lemma 2 (DETACH). Let x=y.px = y.p. If xx is nil, yy is a root and nothing changes. Else let the child list of xx be c1,…,cdc_1, \dots, c_d with y=ciy = c_i. If i=1i = 1, line D2 sets x.left-child=c2x.\text{left-child} = c_2 (nil when d=1d = 1). If i>1i > 1, the loop of line D4 starts at c1c_1 and follows the list; it stops at ci−1c_{i-1}, the first node whose right sibling is yy, after i−2i - 2 steps, because the list is finite by (T2) and contains yy. Line D5 sets ci−1.right-sibling=ci+1c_{i-1}.\text{right-sibling} = c_{i+1}. In both cases the child list of xx is now c1,…,ci−1,ci+1,…,cdc_1, \dots, c_{i-1}, c_{i+1}, \dots, c_d. Line D6 gives (T4) for yy. The fields of the nodes in the subtree of yy other than yy are not touched, so yy is now the root of its old subtree. The cost is O(i)=O(d)O(i) = O(d). □\square

Lemma 3 (CHILDREN). By (T1) and (T2), the variable cc takes the values c1,c2,…,cdc_1, c_2, \dots, c_d, nil, in this order: at the tt-th test of line L6, c=ctc = c_t (and $c = $ nil for t=d+1t = d + 1), by induction on tt with line L7. So line L7 visits the children in order and the loop stops after dd steps. NEW-NODE makes a root with no child, which satisfies (T1) and (T4). □\square

Lemma 4 (the successor in preorder). Let xx be a node in the subtree of rr, and let S(x)S(x) be the node that follows xx in pre(r)\mathrm{pre}(r), or none.

  1. If xx has a child, S(x)=x.left-childS(x) = x.\text{left-child}.
  2. If xx is a leaf, let zz be the first node on the path x,x.p,x.p.p,…x, x.p, x.p.p, \dots that is rr or has a right sibling. If z=rz = r, then xx is the last node of pre(r)\mathrm{pre}(r). Else S(x)=z.right-siblingS(x) = z.\text{right-sibling}.

Proof. Part 1 follows from pre(x)=(x,pre(c1),… )\mathrm{pre}(x) = (x, \mathrm{pre}(c_1), \dots), which is a contiguous part of pre(r)\mathrm{pre}(r) (by induction on the depth of xx below rr, from the recursive definition), and pre(c1)\mathrm{pre}(c_1) starts with c1c_1. For part 2, a leaf xx is the last node of pre(x)\mathrm{pre}(x). For any node v≠rv \ne r in the subtree, let vv be the child cic_i of u=v.pu = v.p. If i<di < d, the part pre(v)\mathrm{pre}(v) in pre(u)\mathrm{pre}(u) is followed by pre(ci+1)\mathrm{pre}(c_{i+1}), which starts with ci+1=v.right-siblingc_{i+1} = v.\text{right-sibling}. If i=di = d, vv has no right sibling, and the last node of pre(v)\mathrm{pre}(v) is also the last node of pre(u)\mathrm{pre}(u). Apply this along the path from xx: as long as the current node v≠rv \ne r has no right sibling, the last node of pre(v)\mathrm{pre}(v), which is xx, is also the last node of pre(v.p)\mathrm{pre}(v.p). At zz: if z=rz = r, xx is the last node of pre(r)\mathrm{pre}(r); else xx is the last node of pre(z)\mathrm{pre}(z) and is followed by z.right-siblingz.\text{right-sibling}. □\square

Lemma 5 (PREORDER). Let pre(r)=(u1,…,um)\mathrm{pre}(r) = (u_1, \dots, u_m) with u1=ru_1 = r. At the tt-th test of line L9, x=utx = u_t for 1≤t≤m1 \le t \le m, and $x = $ nil at the test number m+1m + 1.

Proof. By induction on tt. Line L8 gives x=r=u1x = r = u_1. Assume x=utx = u_t at the tt-th test, t≤mt \le m. Line L10 visits utu_t. If utu_t has a child, line L11 sets xx to S(ut)=ut+1S(u_t) = u_{t+1} by Lemma 4, part 1. Else the loop of line L12 moves xx up the path from utu_t and stops at the first node that is rr or has a right sibling, which is zz of Lemma 4, part 2. It stops because each step moves to the parent, the depth below rr drops by exactly 1, and rr is on the path. Line L13 sets x=z.right-sibling=ut+1x = z.\text{right-sibling} = u_{t+1} if z≠rz \ne r, and $x = $ nil if z=rz = r, which by Lemma 4 happens exactly when t=mt = m. □\square

So PREORDER visits u1,…,umu_1, \dots, u_m, each once, in preorder, and stops.

Lemma 6 (cost of PREORDER). Each node utu_t with t≥2t \ge 2 is reached exactly once by line L11 or line L13, by Lemma 5. A climb x←x.px \leftarrow x.p in line L12 leaves a node v≠rv \ne r whose subtree is finished: by Lemma 4, all nodes visited after it lie outside pre(v)\mathrm{pre}(v), since pre(v)\mathrm{pre}(v) is contiguous and its last node was visited before the climb. A second climb from vv would need x=vx = v again, which is a node of pre(v)\mathrm{pre}(v), and line L12 only moves xx to ancestors of the last visited node, while lines L11 and L13 move it to the next node of the preorder. So each node other than rr is climbed from at most once, and the walk makes at most (m−1)+(m−1)=2(m−1)(m - 1) + (m - 1) = 2(m - 1) moves. With one visit per node, the time is Θ(m)\Theta(m), and the extra space is the one variable xx. □\square

Conclusion. Lemmas 1 to 3 show that each update keeps (T1) to (T4) and that CHILDREN lists the children in order, and Lemmas 5 and 6 show that PREORDER is correct and runs in Θ(m)\Theta(m) time with O(1)O(1) extra space. By induction on the number of operations, any sequence of operations from single-node trees keeps the invariant. ■\blacksquare

Back to Rooted tree representation (left-child right-sibling)