ads note 9.15

Notes on height balance, splaying, and why a costly individual operation can still be inexpensive over a sequence.

Background

Throughout these notes, rotate⁡(X)\operatorname{rotate}(X) means rotating XX with its parent so that XX moves up one level. The rotation preserves the binary search tree’s in-order sequence.

AVL Trees

An empty tree is height-balanced (HB). A nonempty tree TT is height-balanced if and only if both subtrees TLT_L and TRT_R are height-balanced and their heights differ by at most one:

∣hL−hR∣≤1.|h_L-h_R| \le 1.

The balance factor of a node is

BF⁡(v)=hL−hR.\operatorname{BF}(v)=h_L-h_R.

An AVL tree is a binary search tree in which every node satisfies

BF⁡(v)∈{−1,0,1}.\operatorname{BF}(v)\in\{-1,0,1\}.

The four imbalance cases are LL, RR, LR, and RL. LL and RR require a single rotation; LR and RL require a double rotation.

After an insertion, rebalancing the lowest unbalanced ancestor with one single or double rotation restores the tree’s balance. After a deletion, rebalancing may need to continue toward the root.

Splay Trees

When a search finds a node XX, a splay tree moves it to the root. Let PP be its parent and GG its grandparent, when they exist.

There are three cases. The diagrams below omit the attached subtrees; the mirrored cases work symmetrically.

Zig

PP is the root, so XX has no grandparent.

P X
Zig: X is a child of the root.

Perform rotate⁡(X)\operatorname{rotate}(X). Now XX is the root, and splaying is complete.

Zig-zag

XX and PP point in opposite directions: one is a left child and the other is a right child.

G P X
Zig-zag: left, then right.

Perform rotate⁡(X)\operatorname{rotate}(X) twice. This moves XX above both PP and GG.

Zig-zig

XX and PP point in the same direction: both are left children or both are right children.

G P X
Zig-zig: left, then left.

First perform rotate⁡(P)\operatorname{rotate}(P), then rotate⁡(X)\operatorname{rotate}(X). The order matters: this is not the same as rotating XX twice.

After either double rotation, repeat the appropriate case until XX becomes the root. A final zig is needed only if XX ends up one level below the root.

Amortized Analysis

A single operation may be expensive even when a whole sequence is efficient. For example, if nn operations take O(n)O(n) time in total, their amortized cost is O(1)O(1) per operation.

Amortized analysis gives a bound over an operation sequence; it does not require a probability distribution over inputs.

Let cic_i be the actual cost of operation ii, and let c^i\hat{c}_i be its assigned amortized cost. We want the assigned costs to cover the actual total:

∑i=1nc^i≥∑i=1nci.\sum_{i=1}^{n}\hat{c}_i \ge \sum_{i=1}^{n}c_i.

The potential method

Let DiD_i denote the state of the data structure after operation ii. A potential function Φ(Di)\Phi(D_i) measures stored credit in that state. Define

c^i=ci+Φ(Di)−Φ(Di−1).\hat{c}_i=c_i+\Phi(D_i)-\Phi(D_{i-1}).

Equivalently, the credit added during an operation is

c^i−ci=ΔΦi=Φ(Di)−Φ(Di−1).\hat{c}_i-c_i =\Delta\Phi_i =\Phi(D_i)-\Phi(D_{i-1}).

A positive change saves credit; a negative change spends it. Summing over all operations makes the intermediate potential terms cancel:

∑i=1nc^i=∑i=1nci+Φ(Dn)−Φ(D0).\sum_{i=1}^{n}\hat{c}_i =\sum_{i=1}^{n}c_i+\Phi(D_n)-\Phi(D_0).

Thus, Φ(Di)≥0\Phi(D_i)\ge 0 together with Φ(D0)=0\Phi(D_0)=0 is a sufficient condition for the amortized total to upper-bound the actual total. If the initial potential is nonzero, keep that term in the bound.

The potential function is chosen to match the data structure and its expensive operations. It is an analysis tool, not necessarily a value stored by the implementation.

For a stack, choose Φ(S)=∣S∣\Phi(S)=|S|. If a push or a successful pop has unit actual cost, then

c^push=1+1=2,c^pop=1−1=0.\begin{aligned} \hat{c}_{\mathrm{push}}&=1+1=2,\\ \hat{c}_{\mathrm{pop}}&=1-1=0. \end{aligned}

The push pays for itself and saves one unit of credit for the eventual pop.

Amortized Analysis of Splay Trees

The goal is to show an O(log⁡N)O(\log N) amortized bound for splaying in a tree with NN nodes. All logarithms below are base two.

Subtree size, rank, and potential

Let S(v)S(v) be the size of the subtree rooted at vv, including vv itself. Define its rank by

R(v)=log⁡2S(v).R(v)=\log_2 S(v).

Rank measures subtree size on a logarithmic scale. It is not the actual height: a long chain can have linear height but logarithmic rank.

For a single splay step, use subscripts 11 and 22 for the states before and after the step:

ΔR(v)=R2(v)−R1(v).\Delta R(v)=R_2(v)-R_1(v).

Choose the tree’s potential to be

Φ(T)=∑v∈TR(v),ΔΦ(T)=∑v∈TΔR(v).\Phi(T)=\sum_{v\in T}R(v), \qquad \Delta\Phi(T)=\sum_{v\in T}\Delta R(v).

Only the ranks of the nodes participating in the rotations change. We count one unit of actual cost per rotation. The search path has length proportional to the number of rotations, up to an additive constant, so this model suffices for the asymptotic access bound.

We will use the following inequality. For a,b>0a,b>0 and a+b≤ca+b\le c, the arithmetic–geometric mean inequality gives ab≤(c/2)2ab\le(c/2)^2, hence

log⁡2a+log⁡2b≤2log⁡2c−2.\log_2 a+\log_2 b\le 2\log_2 c-2.

Zig: one rotation

The actual cost is ci=1c_i=1, and only XX and PP change rank:

c^i=1+ΔΦ(T)=1+ΔR(X)+ΔR(P).\hat{c}_i =1+\Delta\Phi(T) =1+\Delta R(X)+\Delta R(P).

Since PP‘s subtree shrinks and XX‘s subtree grows, ΔR(P)≤0\Delta R(P)\le 0 and ΔR(X)≥0\Delta R(X)\ge 0. Therefore,

c^i≤1+ΔR(X)≤1+3ΔR(X).\hat{c}_i\le 1+\Delta R(X)\le 1+3\Delta R(X).

Zig-zag: two rotations

Here ci=2c_i=2. After the step, XX contains exactly the subtree that was previously rooted at GG, so R2(X)=R1(G)R_2(X)=R_1(G). These terms cancel:

c^i=2+ΔR(X)+ΔR(P)+ΔR(G)=2−R1(X)+ΔR(P)+R2(G).\begin{aligned} \hat{c}_i &=2+\Delta R(X)+\Delta R(P)+\Delta R(G)\\ &=2-R_1(X)+\Delta R(P)+R_2(G). \end{aligned}

Because R1(P)≥R1(X)R_1(P)\ge R_1(X),

c^i≤2+R2(P)+R2(G)−2R1(X).\hat{c}_i\le 2+R_2(P)+R_2(G)-2R_1(X).

After the rotations, the subtrees rooted at PP and GG are disjoint children of XX, giving

S2(P)+S2(G)=S2(X)−1<S2(X).S_2(P)+S_2(G)=S_2(X)-1<S_2(X).

Applying the logarithmic inequality,

R2(P)+R2(G)≤2R2(X)−2.R_2(P)+R_2(G)\le 2R_2(X)-2.

It follows that

c^i≤2ΔR(X)≤3ΔR(X).\hat{c}_i\le 2\Delta R(X)\le 3\Delta R(X).

Zig-zig: two rotations

Again, ci=2c_i=2 and R2(X)=R1(G)R_2(X)=R_1(G). Using R1(P)≥R1(X)R_1(P)\ge R_1(X) and R2(P)≤R2(X)R_2(P)\le R_2(X) gives

c^i=2−R1(X)+ΔR(P)+R2(G)≤2+R2(X)+R2(G)−2R1(X).\begin{aligned} \hat{c}_i &=2-R_1(X)+\Delta R(P)+R_2(G)\\ &\le 2+R_2(X)+R_2(G)-2R_1(X). \end{aligned}

The old subtree of XX and the new subtree of GG are disjoint parts of the new subtree of XX, so

S1(X)+S2(G)<S2(X).S_1(X)+S_2(G)<S_2(X).

Therefore,

R1(X)+R2(G)≤2R2(X)−2.R_1(X)+R_2(G)\le 2R_2(X)-2.

Substituting this into the cost bound yields

c^i≤3R2(X)−3R1(X)=3ΔR(X).\hat{c}_i\le 3R_2(X)-3R_1(X)=3\Delta R(X).

Summing the steps

Each double rotation costs at most 3ΔR(X)3\Delta R(X) amortized. A zig contributes an additional constant, but it occurs at most once, at the end.

The rank changes telescope across the entire splay. If rr is the original root, then XX‘s final rank equals Rbefore(r)=log⁡2NR_{\mathrm{before}}(r)=\log_2 N. Thus,

c^splay≤1+3(Rafter(X)−Rbefore(X))=1+3(log⁡2N−log⁡2Sbefore(X))≤1+3log⁡2N.\begin{aligned} \hat{c}_{\mathrm{splay}} &\le 1+3\bigl(R_{\mathrm{after}}(X)-R_{\mathrm{before}}(X)\bigr)\\ &=1+3\bigl(\log_2 N-\log_2 S_{\mathrm{before}}(X)\bigr)\\ &\le 1+3\log_2 N. \end{aligned}

This is the access lemma in the unweighted case, giving an O(log⁡N)O(\log N) amortized cost. A single access can still take O(N)O(N) actual time.

For a sequence starting from an arbitrary nonempty tree, Φ(T0)\Phi(T_0) is generally not zero. The total-cost accounting is

∑ici=∑ic^i+Φ(T0)−Φ(Tfinal)≤∑ic^i+Φ(T0).\sum_i c_i =\sum_i\hat{c}_i+\Phi(T_0)-\Phi(T_{\mathrm{final}}) \le\sum_i\hat{c}_i+\Phi(T_0).

For mm accesses on a fixed set of NN nodes, 0≤Φ(T)≤Nlog⁡2N0\le\Phi(T)\le N\log_2 N gives the bound O(mlog⁡N+Nlog⁡N)O(m\log N+N\log N), including the initial potential.

Reference: MIT 6.851 — Splay Trees and the Access Lemma.