CSE3144 Β· Advanced Data Structures Β· Jul–Nov Semester 2026 Β· Lecture 10 of 36 Β· CO CSE3144.2

Splay Trees: the Tree That Learns Your Habits

No balance factors, no colors, no guarantees on any single operation β€” just one rule: whatever you touch, pull to the root. And the payoff Lecture 3 promised: the potential method finally earns its keep.

Dr. Manu ShrivastavaCourse Instructor Β· Consultation Fri 2–5 PM, LHC 308F
~50 minutesSession outcome: apply splaying operations and analyze efficiency
L10 Β· 00 β€” Agenda ~55 min total

Today, minute by minute

The need: real access patterns aren't random

00–05

Locality of reference; zero bookkeeping; where splay trees actually run.

Animation: the three splay steps

05–13

Zig, zig-zig, zig-zag β€” every move on one tree.

Animation: the showdown β€” naive rotate-to-root vs splaying

13–21

Watch the naive fix fail on a chain, then watch splaying fold the chain in half.

Animation: insertion via splaying

21–29

Insert 15, 10, 17, 7 β€” every single rotation of every splay shown on its own.

Animation: top-down deletion via splaying

29–37

Splay the victim out, then join β€” every rotation of both splays shown on its own.

The Lecture 3 callback β€” why "amortized" is the only honest word here

37–42

The battery, formalized: Ξ¦ for splay trees, now that you've watched it work.

Worked example: Ξ¦ on a real tree, cheap vs expensive splay

42–47

The chain from the showdown, numbers in hand: ΔΦ = βˆ’1.585 vs ΔΦ = 0.

Efficiency: the Access Lemma + recap

47–55

Amortized O(log n); the three-tree comparison; homework.

CSE3144 β€” Lecture 10
L10 Β· 01 β€” The need ~5 min

AVL and Red-Black optimize for an enemy that rarely shows up

The observation both of them ignore

Balanced trees treat every key as equally likely to be asked for next. Real workloads don't behave that way: you re-open the same few contacts, a compiler looks up the same identifiers hundreds of times, a router forwards to the same handful of routes β€” the classic 80/20 pattern: 80% of accesses touch 20% of the keys, and what you touched recently, you'll likely touch again (locality of reference).

A balanced tree keeps a key you ask for a thousand times a day at depth 20, forever, because fairness to all keys is its only goal. What if the tree instead moved the popular keys near the root β€” automatically, with no counters, no statistics?

The splay tree's offer (Sleator & Tarjan, 1985)
  • One rule: after every operation β€” search, insert, even a failed search β€” splay the accessed node to the root via special rotations. Hot keys drift up; cold keys sink. The tree is its own cache.
  • Zero bookkeeping: AVL stores a balance factor per node, Red-Black stores a color bit. A splay tree stores nothing β€” plain BST nodes. Simplest code of the three.
  • Used in: Windows NT (memory management), GCC internals, caches, network routers β€” anywhere access patterns are skewed.
  • The honest price: no per-operation guarantee. A single access can cost Θ(n). The tree can even be a chain at some moment. And yet β€” the total over any sequence is provably fast. Hold that thought for the next slide.

Analogy: your kitchen. AVL is the labelled spice rack β€” everything equally reachable, always tidy, effort spent tidying after every use. The splay tree is how kitchens actually work: whatever you used stays in front. The turmeric you use daily is at arm's reach; the star anise from last Diwali has drifted to the back. Nobody maintains this arrangement β€” using things is the arrangement.

CSE3144 β€” Lecture 10
L10 Β· 02 β€” The splay steps ~8 min

Three moves, chosen by where x stands

The decision rule

To splay node x, repeat until x is the root β€” asking, each round, three questions: does x have a grandparent? which side of the parent is x? which side of the grandparent is the parent?

  • Zig / Zag β€” x's parent IS the root: one single rotation (right if x is a left child, left otherwise). The terminal move.
  • Zig-zig / Zag-zag β€” straight line (LL or RR): rotate the grandparent edge first, then the parent edge. Two rotations.
  • Zig-zag / Zag-zig β€” bent path (LR or RL): rotate the parent edge first, then the grandparent edge β€” the same two-rotation repair you used for AVL's bent (LR/RL) cases: it lifts x over the bend while preserving sorted order.

The subtle heart of the algorithm: in the straight-line case, splaying rotates the grandparent first. Plain "rotate x up twice" looks almost identical β€” and destroys the amortized guarantee. The showdown on the next slide exists to prove that this tiny ordering choice is everything.

Interactive β€” zig, zig-zig, zig-zag β€” one tree, three splays
CSE3144 β€” Lecture 10 Β· Splay steps
L10 Β· 03 β€” The showdown ~8 min

Naive rotate-to-root vs splaying β€” same chain, opposite fates

The worst tree we know: the left chain from inserting 6, 5, 4, 3, 2, 1. Both strategies bring the accessed node 1 to the root using rotations. Only one of them deserves to be an algorithm.

Interactive β€” watch the naive fix fail, then watch splaying fold the chain

The takeaway, in Lecture-3 language: both strategies paid the same actual cost to lift node 1. But the naive one left the battery fully charged β€” the same Θ(n) disaster is waiting for the very next access. Splaying spent the potential: the walked path folded, so future accesses into that region are cheap. Expensive operations that repair the structure β€” that is the entire theory of this course paying off in one animation.

CSE3144 β€” Lecture 10 Β· Showdown
L10 Β· 04 β€” Operations: insertion ~8 min

Insert: BST-insert, then splay β€” every rotation on its own

Search(k)

BST search, then splay the found node β€” or, if absent, splay the last node visited before NIL. Even failures reorganize the tree (a failed lookup near k makes the whole neighbourhood of k cheaper next time).

Insert(k)

BST insert (Lecture 7), then splay the new node to the root. Fresh data starts hot β€” usually the right guess. Below: every single rotation from L10·03's decision rule (zig / zig-zig), shown one at a time β€” no two rotations ever collapsed into one step.

Interactive β€” insert 15, 10, 17, 7 β€” every rotation, one click at a time
CSE3144 β€” Lecture 10 Β· Insertion
L10 Β· 04a β€” Operations: deletion ~8 min

Delete: top-down β€” splay the victim out, then join β€” every rotation on its own

Delete(k) β€” top-down

Splay k to the root, remove it β€” leaving left subtree L and right subtree R. Join: splay the maximum of L to L's root (it provably has no right child once it's there!), and hang R directly onto that empty slot. Two splays, no successor-copying, no case analysis. A fresh, larger tree below β€” every rotation of both splays gets its own step.

Interactive β€” top-down delete 16 β€” every rotation, one click at a time
CSE3144 β€” Lecture 10 Β· Deletion
L10 Β· 05 β€” The Lecture 3 callback ~5 min

Remember the battery? This is what it was for.

Recap β€” Lecture 3 in three lines
  • Amortized = worst case over a sequence, no probability. A single operation may be slow if the sequence stays fast.
  • Potential method: pick Ξ¦ = "trouble stored in the structure." Amortized cost Δ‰ = actual cost + ΔΦ. Cheap ops charge the battery; expensive ops run on discharge.
  • Back then we practised on toy examples and told you: "park the doubt β€” a structure is coming that cannot be analyzed any other way." It has arrived β€” you just watched it.
Why splay trees NEED it

A splay tree makes no promise about any single operation β€” an access can cost Θ(n), and no worst-case-per-op analysis can say anything better. AVL had bf-arithmetic; Red-Black had color rules; the splay tree's only defense is: "the expensive access repaired the tree β€” the sequence as a whole stays cheap." That sentence IS amortized analysis. There is no other honest vocabulary for this structure.

The battery, concretely: Ξ¦(tree) = Ξ£ over all nodes of log(size of that node's subtree) β€” the "rank potential." A lopsided chain has HUGE potential (a fully charged battery of trouble); a balanced tree has small potential. An expensive splay of a deep node discharges the battery β€” the tree it leaves behind is flatter, and the discharge pays for the work. Exactly the inverter analogy: metered at the wall socket, every access reads O(log n).

Look back through this lens

Every animation you just watched now reads differently. Zig-zig and zig-zag guarantee that a costly splay leaves the walked path roughly half as deep β€” that's a big drop in Ξ¦, discharging exactly what the deep access spent. The showdown proved naive rotate-to-root doesn't do this β€” no drop in Ξ¦, so it stays stuck at Θ(n) per access forever. Next: the Access Lemma states this discharge precisely.

CSE3144 β€” Lecture 10 Β· The callback
L10 Β· 06 β€” The battery, on a real tree ~5 min

A worked example: Ξ¦ across three splays

Ξ¦(tree) = Ξ£ over every node x of logβ‚‚(size(x)), where size(x) = nodes in x's subtree. Actual cost c(splay(x)) β‰ˆ depth(x). Amortized Δ‰ = c + ΔΦ β€” read it exactly like Lecture 3's PUSH / MULTIPOP table. First two trees: same 6-node chain as the L10Β·03 showdown.

Dβ‚€ β€” start: pure chain
D₁ β€” after splay(1), depth 5β†’0
Dβ‚‚ β€” after splay(6), depth 1β†’0
Splayc (actual)Ξ¦ beforeΞ¦ afterΔΦĉ = c+ΔΦ
splay(1) β€” expensive59.4927.907βˆ’1.5853.415
splay(6) β€” cheap, neutral17.9077.90701

A third case β€” a cheap splay that actually CHARGES the battery: a different 6-node fragment. Root r has a leaf child x (a featherweight, size 1) and a 4-node subtree s that this splay never touches. Splay(x) β€” a single zig.

Before β€” x is a lightweight leaf
After splay(x) β€” x now owns the whole tree
Splayc (actual)Ξ¦ beforeΞ¦ afterΔΦĉ = c+ΔΦ
splay(x) β€” cheap, charges17.1709.492+2.3223.322
Reading it β€” the full spectrum

ΔΦ < 0 β†’ discharge: splay(1) did 5 real units of rotation work, but folded the chain enough that Ξ¦ dropped by 1.585 β€” the meter reads 3.415, close to logβ‚‚6 β‰ˆ 2.58, the O(log n) the Access Lemma promises. ΔΦ = 0 β†’ neutral: splay(6) barely touches the tree's shape and lands exactly on the fence. ΔΦ > 0 β†’ charge: a splay always drags x to the root, and the root's subtree is the whole tree β€” so rank(x) jumps to logβ‚‚n no matter how small x's subtree was. If x was already a heavyweight (splay(6)'s subtree held 5 of 6 nodes), that jump is small and whoever gets demoted can lose a lot β€” net discharge or neutral. But if x is a featherweight leaf next to the root, splaying it is a huge rank gain for x while the demoted ancestor barely shrinks β€” net charge, exactly like Lecture 3's PUSH banking a coin for later.

The one guarantee that never varies: a genuinely deep splay always produces a large negative ΔΦ, because folding a long path in half is precisely what collapses many nodes' subtree sizes at once. Cheap splays near the top are what quietly top the battery back up in between β€” banking exactly the capacity a future deep splay will need to discharge.

CSE3144 β€” Lecture 10 Β· The battery, worked
L10 Β· 07 β€” Efficiency ~4 min

The Access Lemma β€” the payoff, stated

The result (Sleator–Tarjan, 1985)

With rank r(x) = logβ‚‚(size of x's subtree) and Ξ¦ = Ξ£ r(x):

amortized cost of splay(x) ≀ 3Β·(r(root) βˆ’ r(x)) + 1 = O(log n)
  • Hence any sequence of m operations on an n-node splay tree costs O((m + n) log n) β€” deterministic, no probability, any adversarial order. (Compare: naive rotate-to-root admits sequences costing Θ(mΒ·n).)
  • Where the +1 and the 3 come from: only the zig-zig / zig-zag steps make the telescoping work β€” the proof is exactly a Lecture-3 potential argument, three pages long, and every tool it uses β€” ranks, Ξ¦, telescoping β€” is already yours from Lecture 3. Weiss Β§11.5 has the full write-up; bring questions to consultation hours.
  • Bonus (beyond the syllabus): splay trees are statically optimal β€” over a long skewed sequence they perform within a constant of the best fixed tree built with full knowledge of the frequencies.
The Unit II scoreboard so far
AVLRed-BlackSplay
Guaranteeworst-case / opworst-case / opamortized
Height1.44 log n2 log nup to n βˆ’ 1 (!)
Extra storagebf per node1 color bitnone
Adapts to access patternnonoyes β€” its whole point
Single op can be slownonoyes, Θ(n)
Avoid whenwrite-heavyβ€”hard real-time (a single slow op is unacceptable)

Three trees, three philosophies: enforce balance strictly (AVL), enforce it loosely (RB), or don't enforce it at all and let the workload shape the tree (Splay).

CSE3144 β€” Lecture 10 Β· Efficiency
L10 Β· 08 β€” Recap & what's next ~2 min

Three takeaways

Lecture 11

B-Trees, B+ Trees, B* Trees

Unit I meets Unit II: when the tree lives on disk, binary nodes waste the 4 KB block you paid a seek for. Nodes with hundreds of keys β€” the structure inside every database index.

Homework β€” bring to Lecture 11
  • Insert 50, 40, 60, 30, 20 into an empty splay tree, drawing the tree after each splay. Name every step (zig / zig-zig / zig-zag).
  • Take the 7-chain from inserting 7, 6, 5, 4, 3, 2, 1 and splay(1). Then splay(2) on the result. Report the height after each β€” what do you observe?
  • On the final tree of the operations demo: search 13 (present) and search 11 (absent). Show the splays both trigger.
  • Delete 10 from the operations demo's final tree using top-down deletion (splay, remove, join). Show both splays.
  • In 3–4 sentences, Lecture-3 vocabulary mandatory: why is "splay trees are O(log n)" a true statement and "each splay-tree operation is O(log n)" a false one?
  • Reading: Weiss Β§4.5 (splay trees) and Β§11.5 (the amortized proof β€” skim once, then read twice).
CSE3144 β€” Lecture 10

Questions?

Dr. Manu Shrivastava β€” LHC 308F β€” Friday 2:00–5:00 PM

Next: Lecture 11 β€” B-Trees and Variants: the tree that runs your database.