Algorithm Search⌘K

Proofs: Splay tree

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

Splay tree operations take O(log n) amortized time full

This proof shows: amortized-time.

Setting. Give each node weight 1. For a node xx let s(x)s(x) be the number of nodes in its subtree and r(x)=lg⁡s(x)r(x) = \lg s(x). The potential of a tree is Φ=∑xr(x)\Phi = \sum_x r(x), and of a collection of trees the sum over the trees. Each rank is between 0 and lg⁡N\lg N, where NN is the largest number of keys at any time. We count the cost of an operation as the number of nodes visited by its searches plus the number of rotations, plus O(1)O(1); a search that visits d+1d + 1 nodes is followed by a splay of a node at depth dd, which makes dd rotations, so the search costs at most one more than the splay, and it is enough to count rotations plus O(1)O(1).

Access Lemma (Sleator and Tarjan, Lemma 1; proved in the complexity proof of splaying). The amortized number of rotations of a splay of xx in a tree with root tt is at most 3(r(t)−r(x))+1≤3lg⁡N+13(r(t) - r(x)) + 1 \le 3 \lg N + 1.

Access. One splay: at most 3lg⁡N+13 \lg N + 1 amortized, plus O(1)O(1).

Join. The splay of mm in LL costs at most 3lg⁡N+13 \lg N + 1 amortized. Then RR is hung below mm. This changes only the rank of mm, which becomes lg⁡(∣L∣+∣R∣)≤lg⁡N\lg(|L| + |R|) \le \lg N, so the potential grows by at most lg⁡N\lg N. The total is 4lg⁡N+O(1)4 \lg N + O(1).

Split. One access, then one link is cut at the root. Cutting a subtree from the root only lowers the rank of the root, and no other rank changes, so the potential does not grow. The total is 3lg⁡N+O(1)3 \lg N + O(1).

Insert. One access, at most 3lg⁡N+13 \lg N + 1. Then the new node zz becomes the root with the old root rr below it. The rank of rr does not grow (it loses a subtree), no other old rank changes, and zz adds r(z)=lg⁡(n+1)≤lg⁡Nr(z) = \lg(n + 1) \le \lg N. The total is 4lg⁡N+O(1)4 \lg N + O(1).

Delete. One access, at most 3lg⁡N+13 \lg N + 1. Removing the root removes its rank, which only lowers Φ\Phi. Then a join, at most 4lg⁡N+O(1)4 \lg N + O(1). The total is 7lg⁡N+O(1)7 \lg N + O(1).

Sequences. For a sequence of mm operations that starts from a tree with n0n_0 keys, the actual cost is the sum of the amortized costs plus Φ0−Φend\Phi_0 - \Phi_{\text{end}}. Since Φ≥0\Phi \ge 0 and Φ0≤n0lg⁡n0\Phi_0 \le n_0 \lg n_0, the total actual cost is at most m(7lg⁡N+O(1))+n0lg⁡n0=O((m+n0)log⁡N)m(7 \lg N + O(1)) + n_0 \lg n_0 = O((m + n_0) \log N). So each operation costs O(log⁡N)O(\log N) amortized. ■\blacksquare

Remark. The constant 7 for delete is not tight; it comes from adding the bounds of the parts. Other weight choices in the Access Lemma give the static optimality, static finger and working set theorems.

Splay tree operations keep the binary search tree and return the right answers full

This proof shows: correctness, termination.

We use the result of splaying: SPLAY(T,x)(T, x) ends, keeps the strict BST property, the in-order sequence and the parent links, and makes xx the root. Write DD for the set of keys of TT.

Lemma 1 (access). After ACCESS(T,k)(T, k) with D≠∅D \ne \emptyset, the root is the node of kk if k∈Dk \in D; otherwise the root key is floor(k)=max⁡{d∈D:d<k}\mathrm{floor}(k) = \max\{d \in D : d < k\} or ceiling(k)=min⁡{d∈D:d>k}\mathrm{ceiling}(k) = \min\{d \in D : d > k\}. ACCESS returns the node of kk or NIL, correctly.

Proof. The loop of line L2 is the BST search; if k∈Dk \in D it stops at the node of kk and line L4 splays it. If k∉Dk \notin D, the search ends at NIL below the last node ℓ\ell of the path. If the search left ℓ\ell to the left, then k<ℓ.keyk < \ell.key and the left subtree of ℓ\ell is empty. Suppose some key d∈Dd \in D lies strictly between kk and ℓ.key\ell.key. For each node v≠ℓv \ne \ell on the path, kk and ℓ.key\ell.key are on the same side of v.keyv.key, because ℓ\ell is in the subtree that the search for kk entered at vv. So v.keyv.key is not in the closed range from kk to ℓ.key\ell.key, and dd is on the same side of v.keyv.key as kk. Hence dd is in the subtree that the search entered at each vv, so it is in the subtree of ℓ\ell, and as d<ℓ.keyd < \ell.key it is in the empty left subtree of ℓ\ell, a contradiction. So ℓ.key=ceiling(k)\ell.key = \mathrm{ceiling}(k). The case to the right gives the floor. Splaying ℓ\ell makes it the root. Line L5 tests the root key against kk. □\square

Insert. If k∈Dk \in D, line L7 returns and the set does not change. Otherwise, by Lemma 1, the root rr is the floor or the ceiling of kk. If k<r.keyk < r.key, then rr is the ceiling, so every key in the left subtree of rr is less than r.keyr.key and not in (k,r.key)(k, r.key), hence less than kk; the keys of rr and its right subtree are greater than kk. So the tree with root zz, left subtree the old left subtree of rr, and right subtree rr (without its left subtree) has the BST property at zz, and at rr (which lost only a subtree). The case k>r.keyk > r.key is the mirror image. Line L11 sets the parent links. The new key set is D∪{k}D \cup \{k\}.

Join. Let all keys of LL be less than all keys of RR. If $L = $ NIL the answer is RR. Otherwise the maximum mm of LL, after the splay, is the root of LL; it has no right child, since a right child would have a larger key. Hanging RR as its right subtree keeps the BST property at mm, as all keys of RR exceed m.keym.key, and at every other node the subtrees are unchanged.

Delete. If ACCESS returns NIL, k∉Dk \notin D and nothing changes in the set. Otherwise the root holds kk, its left subtree LL holds exactly the keys less than kk and its right subtree RR the keys greater than kk. So JOIN(L,R)(L, R) is legal and gives a BST on D∖{k}D \setminus \{k\}.

Split. After ACCESS, the root rr is the node of kk, or its floor or ceiling, by Lemma 1. If r.key≤kr.key \le k, then rr is kk or its floor, so each key of the right subtree of rr is greater than kk (a key in (r.key,k](r.key, k] would contradict the choice of rr), and each key of rr and its left subtree is at most r.key≤kr.key \le k. So line L19 splits DD into the keys ≤k\le k and >k> k. If r.key>kr.key > k, then rr is the ceiling, so every key in the left subtree of rr is less than kk, and line L20 splits correctly.

Termination. Each search walks down a finite tree, each splay ends, and the walk to the maximum in line L16 walks down a finite tree. ■\blacksquare

Back to Splay tree