Algorithm Search⌘K

Proofs: Finger search tree

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

Finger search takes O(log d) time and updates at a finger take O(1) amortized rebalancing full

This proof shows: complexity, amortized.

Size measure. For a non-root node vv, let c(v)c(v) be its number of children if vv is internal, and its number of keys plus 1 if vv is a bottom node. By (F1) of the correctness proof, 2≤c(v)≤42 \le c(v) \le 4 in a valid tree. During an update, one node at a time can reach c=5c = 5 (overfull, before its split) or c=1c = 1 (underfull, before a share or merge).

Lemma 1 (subtree size). A node at height ii (bottom nodes have height 0) has at least 2i2^i keys below it, unless it is a bottom root.

Proof. A non-root bottom node has at least 1 key, and an internal node has at least 2 children. Induction on ii. □\square

So the height is at most lg⁡n+1\lg n + 1.

Theorem 1 (finger search). Let dd be the number of keys strictly between the range of the finger ff and kk, that is, the keys in (f.hi,k)(f.hi, k) if k>f.hik > f.hi and in (k,f.lo](k, f.lo] if k≤f.lok \le f.lo, and d=0d = 0 if ff holds kk. Then the climb of lines L1 to L5 goes up at most lg⁡d+1\lg d + 1 levels if d≥1d \ge 1, and no levels if d=0d = 0; FINGER-SEARCH takes O(log⁡d+1)O(\log d + 1) time.

Proof. Take k>f.hik > f.hi; the other case is the mirror image. Suppose line L5 moves from a node vv at height ii to its parent. Then vv does not hold kk and, as vv is an ancestor of ff, v.hi≥f.hiv.hi \ge f.hi, and k>v.hik > v.hi by Lemma 1 of the correctness proof (the ranges at one level are in order and ff is below vv). The neighbour w=v.nextw = v.next exists, since the last node of a level has range ending at +∞+\infty, and w.lo=v.hi<kw.lo = v.hi < k while ww does not hold kk, so k>w.hik > w.hi. Every key below ww lies in (v.hi,w.hi]⊆(f.hi,k)(v.hi, w.hi] \subseteq (f.hi, k), and there are at least 2i2^i of them by Lemma 1. So d≥2id \ge 2^i. If the climb reaches height i≥1i \ge 1, it left height i−1i - 1, so d≥2i−1d \ge 2^{i-1} and i≤lg⁡d+1i \le \lg d + 1. If d=0d = 0, no move up happens. The descent from height ii takes ii rounds. Each round of the climb and of the descent looks at O(1)O(1) nodes of at most 4 children, so the time is O(i+1)=O(log⁡d+1)O(i + 1) = O(\log d + 1). □\square

Theorem 2 (rebalancing). Starting from any valid tree, a sequence of mm inserts and deletes, each given the bottom node found by the finger search, does at most O(m)O(m) splits, merges and shares in total, plus 1 per increase of the height.

Proof. Let φ(1)=2\varphi(1) = 2, φ(2)=1\varphi(2) = 1, φ(3)=0\varphi(3) = 0, φ(4)=2\varphi(4) = 2, φ(5)=4\varphi(5) = 4, and Φ=∑vφ(c(v))\Phi = \sum_v \varphi(c(v)) over the non-root nodes vv. Φ≥0\Phi \ge 0 always. The changes of φ\varphi when cc grows by 1 are −1,−1,+2,+2-1, -1, +2, +2 (from c=1,2,3,4c = 1, 2, 3, 4), and when cc drops by 1 they are +1,+1,−2,−2+1, +1, -2, -2 (from c=2,3,4,5c = 2, 3, 4, 5).

  • A key enters or leaves a bottom node: cc changes by 1, so Φ\Phi grows by at most 2.
  • A split of a node with c=5c = 5 gives two nodes with c=3c = 3 and c=2c = 2 (internal) or c=3c = 3 and c=3c = 3 (bottom): Φ\Phi drops by at least 4−1=34 - 1 = 3. The parent gains a child, which adds at most 2. So each split lowers Φ\Phi by at least 1, except a split of the root, where the two halves become non-root nodes and add at most 1 to Φ\Phi; this happens once per increase of the height.
  • A merge of a node with c=1c = 1 and a sibling with c=2c = 2 gives one node with c=3c = 3 (internal: 1+21 + 2 children) or c=2c = 2 (bottom: 0+10 + 1 keys): Φ\Phi drops by at least 3−1=23 - 1 = 2. The parent loses a child, which adds at most 1. So each merge lowers Φ\Phi by at least 1. When the root loses its last but one child, the child becomes the root and leaves the sum, which does not increase Φ\Phi.
  • A share happens at most once per delete, since it ends the delete. The node with c=1c = 1 goes to c=2c = 2 (drop 1) and the sibling drops from c∈{3,4}c \in \{3, 4\} by 1 (change at most +1+1), so Φ\Phi does not increase.

So each update raises Φ\Phi by at most 2 at its start and at most 2 at its last step, and each split or merge in between lowers it by at least 1, except root splits. Summing over the sequence, the number of splits and merges is at most 4m+Φ0+(the number of root splits)4m + \Phi_0 + (\text{the number of root splits}), and Φ0≤2N0\Phi_0 \le 2N_0 for the N0N_0 non-root nodes of the initial tree; from an empty tree Φ0=0\Phi_0 = 0. Each split, merge or share takes O(1)O(1) time, including the change of the level links and of the ranges. ■\blacksquare

Corollary. An insert or a delete at a finger takes O(log⁡d+1)O(\log d + 1) time for the finger search plus O(1)O(1) amortized time for the rebalancing. In particular, building the tree from nn sorted keys, each inserted from the finger of the previous one, takes O(n)O(n) time: the finger search has d=0d = 0 each time, and the root splits number at most lg⁡n+1\lg n + 1.

Finger search and updates in a level-linked (2,4)-tree are correct full

This proof shows: correctness, invariant, termination.

Write (v.lo,v.hi](v.lo, v.hi] for the range of node vv, with −∞-\infty and +∞+\infty allowed. The invariant has three parts.

  • (F1) Shape. All bottom nodes are at the same depth. A non-root bottom node has 1 to 3 keys; an internal node has 2 to 4 children and one separator fewer; the root may be a bottom node with 0 to 3 keys.
  • (F2) Ranges. The root has range (−∞,+∞](-\infty, +\infty]. An internal node vv with children c0,…,cm−1c_0, \ldots, c_{m-1} and separators s1<⋯<sm−1s_1 < \cdots < s_{m-1} has cj.lo=sjc_j.lo = s_j and cj.hi=sj+1c_j.hi = s_{j+1}, where s0=v.los_0 = v.lo and sm=v.his_m = v.hi. The keys of a bottom node are increasing and lie in its range.
  • (F3) Levels. For each depth, nextnext and prevprev link the nodes of that depth in left-to-right order.

Lemma 1. Under (F1) to (F3), the ranges of the nodes of one depth are disjoint and their union is (−∞,+∞](-\infty, +\infty], and the left-to-right order of the nodes is the order of their ranges. The range of a node contains the ranges of its descendants.

Proof. By induction on the depth. At depth 0 it is the root. If it holds at depth tt, (F2) splits each range at depth tt into the ranges of the children, in order, so it holds at depth t+1t + 1. □\square

Lemma 2 (DESCEND). If v.lo<k≤v.hiv.lo < k \le v.hi, DESCEND(v,k)(v, k) returns the bottom node below vv whose range holds kk.

Proof. Line L8 picks the least jj with k≤sj+1k \le s_{j+1} (with sm=v.hi≥ks_m = v.hi \ge k, so jj exists). Then k>sjk > s_j: for j=0j = 0 because s0=v.lo<ks_0 = v.lo < k, and for j>0j > 0 by the choice of jj. So cjc_j holds kk in its range, and the loop keeps the condition. The depth grows each round, so the loop ends at a bottom node, and by Lemma 1 it is the only bottom node whose range holds kk. □\square

Lemma 3 (FINGER-SEARCH). FINGER-SEARCH(f,k)(f, k) ends and returns the bottom node whose range holds kk.

Proof. Each round of lines L2 to L5 either stops (line L4 or the test of line L2) at a node whose range holds kk, or moves to the parent. The root's range holds kk, so the climb ends after at most the height of the tree. Then Lemma 2 applies. □\square

So a search reports kk present exactly when kk is a key of the returned bottom node, because by (F2) and Lemma 1, a key kk can only be in the bottom node whose range holds it.

Insert. If kk is already in bb, nothing changes. Else line L12 puts kk into bb in sorted order, and kk lies in the range of bb by Lemma 3, so (F2) holds. Only the size condition of (F1) can fail, and only at vv. Line L15 splits vv:

  • a bottom node with keys a1<a2<a3<a4a_1 < a_2 < a_3 < a_4 becomes v=(a1,a2)v = (a_1, a_2) and u=(a3,a4)u = (a_3, a_4), with s=a2s = a_2; the ranges (v.lo,a2](v.lo, a_2] and (a2,v.hi](a_2, v.hi] hold the keys;
  • an internal node with children c0,…,c4c_0, \ldots, c_4 and separators s1,…,s4s_1, \ldots, s_4 becomes vv with c0,c1,c2c_0, c_1, c_2 and s1,s2s_1, s_2, and uu with c3,c4c_3, c_4 and s4s_4, with s=s3s = s_3; the children keep their ranges, which satisfy (F2) in vv and uu, since c2.hi=s3=v.hic_2.hi = s_3 = v.hi and c3.lo=s3=u.loc_3.lo = s_3 = u.lo.

Linking uu just after vv keeps (F3). Line L17 puts uu after vv in the parent with ss between them, so the parent's separators become …,v.lo,s,v.hi,…\ldots, v.lo, s, v.hi, \ldots around vv and uu, which is (F2) for the parent; they stay increasing because v.lo<s<v.hiv.lo < s < v.hi. The parent has one more child and may now be overfull, which the next round handles. A split of the root (line L16) makes a new root with range (−∞,+∞](-\infty, +\infty] and children vv, uu, one level higher; all bottom nodes stay at one depth. Each round goes one level up, so the loop ends. Line L19 returns the half of the split bottom node that holds kk.

Delete. If kk is not in bb, nothing changes. Else removing kk keeps (F2) at bb. Only the minimum size can fail, at a non-root node vv with parent pp and adjacent sibling ww; say ww is left of vv (the other case is the mirror image), with separator tt between them in pp, so w.hi=t=v.low.hi = t = v.lo.

  • Share, bottom. The largest key xx of ww moves into vv; the new separator is $t' = $ the new largest key of ww, with w.hi=v.lo=t′w.hi = v.lo = t'. The keys of ww are ≤t′\le t', and the keys of vv, now xx and the old ones, are >t′> t', since xx was the largest key of ww and the old keys of vv are >t≥x> t \ge x. So (F2) holds.
  • Share, internal. The last child cc of ww, with range (t′,t](t', t], where t′t' is the last separator of ww, becomes the first child of vv; tt moves down as the first separator of vv, and t′t' goes up into pp in the place of tt, with w.hi=v.lo=t′w.hi = v.lo = t'. Each child keeps its range, and the ranges match the new separators. (F3) does not change: cc stays at its place in its level.
  • Merge. vv joins ww: the keys (bottom) or the children with tt between the two lists of separators (internal) go into ww, with $w.hi = $ old v.hiv.hi; tt leaves pp; vv is unlinked from its level. The ranges of the children do not change and match the new separators of ww, the keys of vv lie in its old range, which is now part of the range of ww, and the level order of the other nodes stays. The parent has one child fewer and may now be underfull, which the next round handles.

The sizes after a share or merge are in the bounds of (F1), because a share takes from a sibling above the minimum, and a merge joins a node below the minimum with a sibling at the minimum (0 + 1 keys or 1 + 2 children). If the root is left with one child, its range is the root's range (−∞,+∞](-\infty, +\infty] by (F2), so making it the root keeps (F2), and all bottom nodes stay at one depth. Each round goes one level up, so the loop ends. The bottom node returned is bb or the node bb merged into; in both cases its range contains the old range of bb, which holds kk. ■\blacksquare

Back to Finger search tree