Today’s Outline
CSE 326: Data Structures • TO DO
– Finish Homework #1;
due Friday at the beginning of class
Topic #7: – Find a partner for Project #2;
send me email by Friday evening
Don’t Sweat It, Splay It!
• Review AVL Trees
Ashish Sabharwal • Splay Trees
Autumn, 2003
AVL Trees Revisited AVL Trees Revisited
• Balance condition: • What extra info did we maintain in each node?
For every node x, -1 ≤ balance(x) ≤ 1
– Strong enough : Worst case depth is (log n)
– Easy to maintain : one single or double rotation • Where were rotations performed?
• Guaranteed (log n) running time for
– Find ?
• How did we locate this node?
– Insert ?
– Delete ?
– buildTree ?
3 4
Other Possibilities? Splay Trees
• Could use different balance conditions, different ways to • Blind adjusting version of AVL trees
maintain balance, different guarantees on running time, … – Why worry about balances? Just rotate anyway!
• Amortized time per operations is O(log n)
• Why? Aren’t AVL trees perfect?
• Worst case time per operation is O(n)
– But guaranteed to happen rarely
• Many other balanced BST data structures
– Red-Black trees Insert/Find always rotate node to the root!
– AA trees
– Splay Trees
Subject GRE Analogy question:
– 2-3 Trees
– B-Trees
AVL is to Splay trees as ___________ is to __________
– … 5 6
1
Recall: Amortized Complexity Recall: Amortized Complexity
If a sequence of M operations takes O(M f(n)) time, • Is amortized guarantee any weaker than worstcase?
we say the amortized runtime is O(f(n)).
• Is amortized guarantee any stronger than averagecase?
• Worst case time per operation can still be large, say O(n)
• Worst case time for any sequence of M operations is O(M f(n)) • Is average case guarantee good enough in practice?
Average time per operation for any sequence is O(f(n)) • Is amortized guarantee good enough in practice?
Amortized complexity is worst-case guarantee over
sequences of operations.
7 8
The Splay Tree Idea Find/Insert in Splay Trees
10 1. Find or insert a node k
2. Splay k to the root using:
If you’re forced to make 17 zig-zag, zig-zig, or plain old zig rotation
a really deep access:
Since you’re down there anyway,
fix up a lot of deep nodes! Why could this be good??
5 1. Helps the new root, k
2 9
o Great if x is accessed again
3
2. And helps many others!
o Great if many others on the path are accessed
9 10
Splaying node k to the root: Splaying node k to the root:
Need to be careful! Need to be careful!
One option is to repeatedly use AVL single rotation What’s bad about this process?
until k becomes the root: (see Section 4.5.1 for details)
p
k
q p k
F
r q
s p F
E s p
r
s q E
D A B s q
F A B F
D
k r r
A E k
A E
B C C D B C C D
11 12
2
Splay: Zig-Zag* Splay: Zig-Zig*
g k
g k
p p
W Z
p g p
X k g
X Y
k
W X Y Z W
Y Z W X
Y Z *Is this an AVL zig-zig? How to implement?
*Just like an… Which nodes improve depth?
13
Why does this help? 14
Special Case for Root: Zig Does Splaying Help Every Node?
root p k root
k p
Z X
X Y Y Z
Only amortized guarantee!
Relative depth of p, Y, Z? Relative depth of everyone else?
Let’s see an example…
Why not drop zig-zig and just zig all the way?
15 16
Splaying Example: Find(6) Still Splaying 6
1 1
1 1
2 2
? 2 6
?
3 3
Find(6) 3 3
4 6
6 2 5
5 5
5 4
6 4
17 4 18
3
Finally… Another Splay: Find(4)
1 6 6 6
6 1 1 1
? ?
3 3 3 4
Find(4)
2 5 2 5 2 5 3 5
4 4 4 2
19 20
Example Splayed Out But Wait…
What happened here?
6 4
Didn’t two find operations take linear time
1 1 6 instead of logarithmic?
?
4 3 5
What about the amortized (log n) guarantee?
3 5 2
21 22
Why Splaying Helps Practical Benefit of Splaying
• If a node n on the access path is at depth d before • No heights to maintain, no imbalance to check for
the splay, it’s at about depth d/2 after the splay – Less storage per node, easier to code
– Exceptions are the root, the child of the root (and
descendants), and the node splayed
• Often data that is accessed once,
is soon accessed again!
• Overall, nodes which are low on the access path – Splaying does implicit caching by bringing it to the root
tend to move closer to the root
23 24
4
Splay Operations: Find Splay Operations: Insert
• Find the node in normal BST manner • Insert the node in normal BST manner
• Splay the node to the root • Splay the node to the root
– if node not found, splay what would have been its parent
What if we didn’t splay?
What if we didn’t splay?
25 26
Splay Operations: Remove Join
Join(L, R): given two trees such that L < R, merge them
splay L
k
find(k) delete k max
L R R
L R
L R <k >k
Splay on the maximum element in L, then attach R
Now what? Does this work to join any two trees?
27 28
Delete Example A Nifty Splay Operation:
Delete(4)
6 4 6 Splitting
1 9 find(4) 1 6 1 9 Split(T, k) creates two BSTs L and R:
– all elements of T are in either L or R (T = L ∪ R)
4 7 2 9 2 7 – all elements in L are ≤ k
– all elements in R are ≥ k
Find max
2 7 – L and R share no elements (L ∩ R = ∅)
2 2
How do we split a splay tree?
1 6 1 6
9 9
7 7 29 30
5
Splitting Splays Aha, Another Way to Insert!
split(k)
Insert(k)
splay k
split(k)
T L R
L R
<k >k L R
void split(Node * root, Node *& left,
Node *& right, Object k) {
Node * target = root->find(k);
splay(target);
if (target < k) { OR
void insert(Node *& root, Object k) {
left = target->left;
Node * left, * right;
target->left = NULL;
split(root, left, right, k);
right = target; L R L R
root = new Node(k, left, right); Interesting note: split-and-insert was
}
... ≤x >x <x ≥x } the original algorithm. But insert-
31 32
and-splay has better constants
}
Splay Tree Summary To Do
• All operations are in amortized (log n) time
• Finish reading Chapter 4
• Splaying can be done top-down; better because:
• Homework #1 due Friday
– only one pass
• Project #2 will be released Friday
– no recursion or parent pointers necessary
– Pick a partner!
– we didn’t cover top-down in class
• Splay trees are very effective search trees
– Relatively simple
– No extra fields required
– Excellent locality properties: frequently accessed keys are
cheap to find 33 34