Algorithm Search⌘K

Proofs: DFUDS

These are the human proofs of DFUDS, at full length.

Correctness of navigation on DFUDS full

This proof shows: correctness.

Let U=( code(v0)⋯code(vn−1)U = (\, \text{code}(v_0) \cdots \text{code}(v_{n-1}) with code(v)=(d(v))\text{code}(v) = (^{d(v)} ) and the nodes in preorder. For a node vv let s(v)s(v) be the start of its code and T(v)T(v) the concatenation of the codes of the subtree of vv, which is a contiguous segment of UU because preorder lists each subtree contiguously, starting at s(v)s(v).

Lemma 1. T(v)T(v) has one more ) than (, every proper prefix of T(v)T(v) has at least as many ( as ), and so ( T(v)(\,T(v) is balanced. By induction on the height. If vv is a leaf, T(v)=)T(v) = ). Otherwise T(v)=(d) T(c1)⋯T(cd)T(v) = (^{d} )\, T(c_1) \cdots T(c_d) for the children c1,…,cdc_1, \ldots, c_d. After (d)(^{d} ) the excess relative to the start is d−1d - 1, and each T(cj)T(c_j) lowers it by exactly one without going below its starting value minus one, by induction. So the excess relative to the start goes d−1,d−2,…,−1d - 1, d - 2, \ldots, -1 at the ends of the T(cj)T(c_j), and is ≥0\ge 0 before the last symbol. With the leading (, U=( T(v0)U = (\, T(v_0) is balanced.

Lemma 2 (matching). Let vv have children c1,…,cdc_1, \ldots, c_d, d≥1d \ge 1, and let ee be the position of the ) of code(v)\text{code}(v), so that s(c1)=e+1s(c_1) = e + 1 and s(ci)s(c_i) is one past the end of T(ci−1)T(c_{i-1}). For 1≤i≤d1 \le i \le d, the ( at e−ie - i matches the ) at s(ci)−1s(c_i) - 1.

Let R(t)R(t) be the number of ( minus the number of ) in U[e−i..t]U[e - i..t]; the match of e−ie - i is the least t>e−it > e - i with R(t)=0R(t) = 0. The positions e−i,…,e−1e - i, \ldots, e - 1 are (, so R≥1R \ge 1 there, and R(e)=i−1R(e) = i - 1. If i=1i = 1, the match is e=s(c1)−1e = s(c_1) - 1. If i>1i > 1, then by Lemma 1 each T(cj)T(c_j) lowers RR by exactly one and keeps it at or above its starting value inside, so R=i−1−jR = i - 1 - j at the end of T(cj)T(c_j) and R≥i−jR \ge i - j before that end. For j<i−1j < i - 1 all these values are at least 1, and at the end of T(ci−1)T(c_{i-1}), which is s(ci)−1s(c_i) - 1, RR is 0 for the first time.

Likewise the leading ( at position 0 matches the last position of UU, by Lemma 1, and s(v0)=1s(v_0) = 1.

DEGREE (L1). There are rank)(s(v))\text{rank}_)(s(v)) codes before vv, so the ) ending code(v)\text{code}(v) is the next one, at e=select)(rank)(s(v))+1)e = \text{select}_)(\text{rank}_)(s(v)) + 1), and code(v)\text{code}(v) has e−s(v)e - s(v) symbols (.

CHILD (L2-L4). By Lemma 2, findclose(e−i)=s(ci)−1\text{findclose}(e - i) = s(c_i) - 1.

PARENT (L5-L7). For v≠v0v \ne v_0 with parent pp and v=civ = c_i, Lemma 2 says the ) at s(v)−1s(v) - 1 is matched by the ( at ep−ie_p - i, which lies in code(p)\text{code}(p). The number of ) before that position is the number of codes before code(p)\text{code}(p), rank)(o)\text{rank}_)(o), so code(p)\text{code}(p) starts right after the rank)(o)\text{rank}_)(o)-th ), or at 1 if that number is 0, by the convention select)(0)=0\text{select}_)(0) = 0.

CHILD-RANK (L8-L9). With o=ep−io = e_p - i, the ) ending code(p)\text{code}(p) is ep=select)(rank)(o)+1)e_p = \text{select}_)(\text{rank}_)(o) + 1), so i=ep−oi = e_p - o.

SUBTREE-SIZE (L10-L11). fwdsearch(s(v)−1,−1)\text{fwdsearch}(s(v) - 1, -1) is the first position after s(v)−1s(v) - 1 where the excess falls one below its value at s(v)−1s(v) - 1. By Lemma 1, inside T(v)T(v) the excess stays at or above its value at s(v)−1s(v) - 1 and falls one below it exactly at the last symbol of T(v)T(v). So endend is the last position of T(v)T(v), and since T(v)T(v) has s−1s - 1 ( and ss ) for a subtree of ss nodes, end−s(v)+1=2s−1end - s(v) + 1 = 2s - 1.

Space. ∣U∣=1+∑v(d(v)+1)=1+(n−1)+n=2n|U| = 1 + \sum_v (d(v) + 1) = 1 + (n - 1) + n = 2n. ■\blacksquare

Back to DFUDS