Algorithm Search⌘K

Proofs: Scapegoat tree

These are the human proofs of Scapegoat tree, at full length.

The scapegoat tree keeps its keys and its depth bound full

This proof shows: correctness.

Fix α\alpha with 12<α<1\frac12 < \alpha < 1, and write log⁡\log for log⁡1/α\log_{1/\alpha}. The depth of the root is 0, and size(x)\text{size}(x) is the number of nodes in the subtree of xx. The tree keeps two counters, nn and qq. We show that after each operation the following hold.

  1. (S1) The tree is a binary search tree whose keys are the keys inserted and not deleted, and nn is their number.
  2. (S2) αq≤n≤q\alpha q \le n \le q.
  3. (S3) Each node has depth at most log⁡q\log q.

All three hold for the empty tree with n=q=0n = q = 0 (there are no nodes, so (S3) holds).

Rebuilding. REBUILD(w)(w) lists the nodes of the subtree of ww in key order (line L9) and links them again by BUILD (line L10). BUILD puts a[mid]a[mid] at the root, the nodes left of midmid in its left subtree and those right of midmid in its right subtree, so by induction on hi−lohi - lo the result is a search tree on the same nodes in the same order. Its two subtrees have sizes that differ by at most one, so a tree on m≥1m \ge 1 nodes has height ⌊lg⁡m⌋\lfloor \lg m \rfloor, the least possible height of a binary tree on mm nodes. Rebuilding does not change the key set or the order, and only the depths of nodes inside the rebuilt subtree change.

Lemma 1. Let uu be a node of depth d>log⁡qd > \log q in a tree with n≤qn \le q nodes. Then some proper ancestor ww of uu has a child cc on the path to uu with size(c)>α⋅size(w)\text{size}(c) > \alpha \cdot \text{size}(w).

Proof. Let x0=u,x1,…,xdx_0 = u, x_1, \ldots, x_d be the path from uu up to the root. If size(xj−1)≤α⋅size(xj)\text{size}(x_{j-1}) \le \alpha \cdot \text{size}(x_j) for all jj, then size(xd)≥(1/α)d size(x0)=(1/α)d>q≥n\text{size}(x_d) \ge (1/\alpha)^d \, \text{size}(x_0) = (1/\alpha)^d > q \ge n, which is not possible, since the root has nn nodes. □\square

So the loop of line L4 always stops at a node ww, and ww is the first such ancestor met when walking up from uu.

Insertion. If kk is present, line L1 returns and nothing changes. Otherwise a leaf uu with key kk is attached where the search ended, which keeps (S1), and line L2 adds one to nn and qq, which keeps (S1) and (S2), because α(q+1)≤n+1≤q+1\alpha(q + 1) \le n + 1 \le q + 1 follows from αq≤n≤q\alpha q \le n \le q and α<1\alpha < 1. Let qq now denote the new value. The old nodes keep their depths, which are at most the old log⁡(q−1)<log⁡q\log(q - 1) < \log q. Let dd be the depth of uu. If d≤log⁡qd \le \log q, (S3) holds and line L3 does nothing.

Otherwise d>log⁡qd > \log q. The parent of uu is an old node, so d−1≤log⁡qd - 1 \le \log q, and uu is the only node of depth more than log⁡q\log q. By Lemma 1, line L4 finds ww; let dwd_w be its depth, i=d−dw≥1i = d - d_w \ge 1 the depth of uu below ww, m=size(w)m = \text{size}(w), and cc the child of ww on the path to uu, with size(c)>αm\text{size}(c) > \alpha m.

Claim: m<2im < 2^i. Before uu was attached, the subtree of ww had m−1m - 1 nodes, all at depth at most d−1d - 1 in the tree, that is at most i−1i - 1 below ww. A binary tree of height at most i−1i - 1 has at most 2i−12^i - 1 nodes, so m−1≤2i−1m - 1 \le 2^i - 1. If m−1=2i−1m - 1 = 2^i - 1, that old subtree was the perfect tree of height i−1i - 1, in which both children of ww have 2i−1−12^{i-1} - 1 nodes. Then after the insertion size(c)=2i−1=m/2<αm\text{size}(c) = 2^{i-1} = m / 2 < \alpha m, a contradiction. So m≤2i−1m \le 2^i - 1.

By the claim, the rebuilt subtree has height ⌊lg⁡m⌋≤i−1\lfloor \lg m \rfloor \le i - 1. Its nodes, uu among them, now have depth at most dw+i−1=d−1≤log⁡qd_w + i - 1 = d - 1 \le \log q. The nodes outside the subtree of ww keep their depths, which are at most log⁡q\log q. So (S3) holds, and by the paragraph on rebuilding, (S1) holds.

Deletion. If kk is absent, line L6 returns and nothing changes. Otherwise line L6 is the deletion of a binary search tree: a node with at most one child is replaced by that child, and a node with two children takes the key of its successor, whose node, which has no left child, is replaced by its right child. This keeps (S1). Each node keeps its depth or moves up one level, so no depth grows, and since qq is unchanged, (S3) holds. Line L7 makes nn the new count. Now n≤qn \le q still holds. If n≥αqn \ge \alpha q, (S2) holds and line L8 does nothing. Otherwise line L8 rebuilds the whole tree and sets q=nq = n, so (S2) holds with equality. The new tree has height ⌊lg⁡n⌋≤log⁡n=log⁡q\lfloor \lg n \rfloor \le \log n = \log q, since 1/α<21/\alpha < 2, and so (S3) holds. If n=0n = 0, the tree is empty.

Theorem. After any sequence of operations from the empty tree, the tree holds exactly the keys inserted and not deleted, CONTAINS answers correctly, and the height is at most log⁡1/αq≤log⁡1/αn+1\log_{1/\alpha} q \le \log_{1/\alpha} n + 1.

Proof. The cases above show that (S1) to (S3) hold after each operation. CONTAINS is the search of a binary search tree, which is correct by (S1). By (S2), q≤n/αq \le n/\alpha, so log⁡q≤log⁡n+1\log q \le \log n + 1. ■\blacksquare

Back to Scapegoat tree