and AVL Trees The Most Beautiful Data Structures in the World This animation is a PowerPoint slideshow Hit the spacebar to advance Hit the backspace key to go backwards Hit the ESC key to terminate the show ID: 635699
Download Presentation The PPT/PDF document "Binary Trees, Binary Search Trees," is the property of its rightful owner. Permission is granted to download and print the materials on this web site for personal, non-commercial use only, and to display it on your personal computer provided you do not modify the materials and that you retain all copyright notices contained in the materials. By downloading content from our website, you accept the terms of this agreement.
Slide1
Binary Trees,Binary Search Trees, and AVL Trees
The Most Beautiful Data Structures in the World
This animation is a PowerPoint slideshow
Hit the spacebar to advance
Hit the backspace key to go backwards
Hit the ESC key to terminate the show
This is a PowerPoint slideshow with extensive animation; it is meant to be viewed in slideshow mode. If you’re reading this text, you’re not in slideshow mode. Enter slideshow mode by hitting function key 5 on your keyboard (the F5 key)Slide2
AVL Trees: Motivation
AVL trees, named after the two mathematicians Adelson-Velsky and Landis who invented/discovered them, are of great theoretic, practical, and historic interest in computer science as they were the first data structure to provide efficient —
i.e., O(lg n) — support for the big three of data structure operations: search, insertion, and deletionThe proof of their O(lg
n) behavior illuminates the complex and beautiful topological properties that an abstract data structure can have
This presentation provides an overview of that proof — along with a decent review of some of the basics of binary trees along the way
V
A
D
P
W
K
C
L
F
T
E
J
MSlide3
Roadmap
V
A
D
P
W
K
C
L
F
T
E
J
M
Binary trees in general
Definitions, vocabulary, properties
The range of possible heights for binary trees (and why we care)
Binary search trees
The search (or find) algorithm
Insertion
Deletion
The problem (or why we need AVL trees)
AVL trees
Definition: An HB(1) binary search tree
O(1) rebalancing to restore the HB(1) property after the BST insertion
Finding the deepest node out of balance in O(h) time
Proof that the HB(1) property means that h is O(
lg
n)
Some engineering implications of AVL tree propertiesSlide4
Binary Trees
A binary tree is an abstract data structure that is either empty or has a unique root with exactly two
subtrees
, called the left and the right
subtrees
, each of which is itself a binary tree (and so may be empty)
Here are illustrations of some typical binary trees:
Note that the definition for a binary tree is recursive — unlike
trees from graph theory which
are defined based on graph
theoretic properties alone (no recursion)
Thus
it is technically correct to say that a binary tree is not
a graph and hence is not really
a tree
no
one but me ever says that anymore; but although it’s not particularly important, it’s still the truth, so I want you to know
it
The empty binary tree
A binary tree having a root with two empty subtrees
A binary tree having a root with a non-empty left subtree
and an empty
right subtree
Note that this is a different binary tree than the one to the left
The root in this one has an empty left
subtree
but a non-empty right one
Doesn’t look particularly “binary”, but it’s still a binary tree
—
just one
with
every node having an empty right
subtreeSlide5
Properties and Nomenclature
of Binary Trees and Nodes
We’ll often use genealogical terminology when referring to nodes and their relationships
0
1
2
3
4
5
level
#
h=5
Nodes can be categorized by level, starting with the root at level 0
A node
with
descendants is called an interior or internal node
The depth of a node is its level number; which is the number of edges (path length) between the node and the root
This node is at level
4
and so has a depth
of 4
Topologic
properties
of nodes and trees will be important too
The left (or right) child of a given node plus all that child’s descendants are collectively referred to as the left (or right) descendants of the original node
The highlighted subtree contains the left descendants of this node
The height of a binary tree is the depth of its deepest node; so this binary tree has a height of 5
Two more or less obvious consequences of this definition:
The height of any leaf is 0
The height of the root is the height of the whole tree
A node with two children is said
to be full
A full binary tree is one where all internal nodes are full
—
so there are no nodes with just one child, everybody is either a leaf or full
Although this particular node is full, the tree here is not
There are many additional topologic properties (also called “shape” properties) that we’ll be defining and working with, such as the relationship between a binary tree’s height and its number of nodes, which we’ll examine next
A node is the parent of its children
This node has a left child but no right child
This node also has a sibling, a node with the same parent
A node with no descendants is called an external or leaf node
Every node except the root has
a
unique parent
A
node may or may not have
descendants; but every node except the root has one or more ancestors
The height of a node is the path length to its deepest descendant
This node has height
2Slide6
Roadmap
V
A
D
P
W
K
C
L
F
T
E
J
M
Binary trees in general
Definitions, vocabulary, properties
The range of possible heights for binary trees (and why we care ;-)
Binary search trees
AVL treesSlide7
Range of Possible Heights for Binary Trees (and Why We Care)
The height and number of nodes in a binary tree are obviously related
For any given number of nodes, n, there is a minimum and a maximum possible height for a binary tree which contains that number of nodes – e.g., a binary tree with 5 nodes can’t have height 0 or height 100Contra wise, for any given height, h, there is a minimum and maximum number of nodes possible for that height – e.g., a binary tree with height 2 can’t have 1 node or 50 nodes in it
We’re very interested in the minimum and maximum possible heights for a binary tree because when we get to search trees (soon) it will be easy to see that search and insertion performance are O(h); the tougher question will be, what are the limitations on h as a function of n?
Large h leads to the poor performance
Small h will result in good performanceSlide8
Maximum Possible Height
It’s easy to see that the greatest possible height for a binary tree containing n nodes is h =
n -1
n=4, h=3
The
minimum
possible height (the best case for O(h) performance) is a bit more interesting
For maximum height, we want the maximum number of levels, so each level should contain the fewest possible nodes — which is to say 1, since a level cannot be empty
So the tallest tree having n nodes would have n levels
The largest level # would then be n-1, since we start numbering levels with the root at level 0
So the maximum height for a binary tree containing n nodes is h
=
n-1Slide9
An almost perfect binary tree is the most compact of all binary trees, it has the minimum possible height for its number of nodes
So to know the minimum possible height for
any
binary tree of n nodes, all we have to do is figure out the (unique) height of an
almost perfect
binary tree with n nodes
Two Necessary Definitions Along the Way
(to the Minimum Possible Height for a Binary Tree)
A
perfect
binary tree has the maximum possible number of nodes at every level
An
almost perfect
(also known as complete) binary tree has the maximum number of nodes at each level except the lowest, where all the nodes are “left justified”
Note:
If we add another node to this almost perfect tree, there’s only one place it could go and still keep the tree almost perfect by keeping the bottom level all left justified
So for any given number of nodes, n, there is only one almost perfect binary tree with n nodes
— the shape is unique
Since the shape is unique, the best case and worst case heights are the same: Given a number of nodes, n, there’s only one possible height for an almost perfect binary tree of that given number of nodes
To reduce the height of this almost perfect binary tree, all the nodes here at the bottom would have to go into a higher level somewhere; but they can’t
— by definition, all the upper levels already contain their maximum possible number of nodesSlide10
level 2 has
2
2
= 4
nodes
level 0 has 2
0
=1 nodes
level 3 has
2
3
=
8 nodes
level 4 has
2
4
=
16
nodes
level k has 2
k nodes
level 1 has
2
1
=
2
nodes
•
•
•
Although what we’re really after is the height of an almost perfect binary tree, we need to know the number of nodes in a perfect binary tree first (trust me on this ;-)
The number of nodes in a binary tree (any binary tree) is obviously the sum of the number of nodes in all its levels, so a perfect binary tree with height h,
which has
levels 0 through h, has a total number of
nodes n =
l
k
,
where
l
k
is
the
number
of nodes at level
k
=
2
k
=
2
h+1
-1
h
k=0
h
k=0
Total Number of Nodes in a Perfect Binary Tree
Note that a perfect binary tree is also a full binary tree
Every interior node has 2 children
If there were an interior node that
didn’t
have 2 children, the level beneath it would not have the maximum possible number of nodes
Since all internal nodes are full and there are no leaves except at the bottom level, each level has twice as many nodes as the one above itSlide11
h-1
Height of an Almost Perfect Binary Tree
Special Case
Consider first the special case of an almost perfect binary tree whose bottom level has only a single node in it
The rest of this tree above the bottom level is obviously a perfect binary tree of height h-1
h
So, adding in the single node at the bottom level, in this special case n = 2
h
nodes
Taking the binary logarithm of both sides, we get
h = log
2
n
Since this “upper” portion is a perfect binary tree of height h-1, it has
2
k = 2(h-1)+1
-1 = 2h -1 nodes
h
-1
k=0Slide12
The height h has remained the same even though log2 n has grown
But log2
n can’t have grown as large as h+1; it won’t get that big until we fill the last level completely and have to add the next node to a new lowest level
Since h is an integer, we can express h ≤ log
2n < h+1 as
h = log2
n, where x
is the “floor” function, the largest integer ≤ x
Suppose there’s more than one node on the bottom level?
In between, as the bottom level fills up, h
≤
log2n < h+1
Height of an Almost Perfect Binary Tree
General Case
h
h+1
Now
the overall height has grown to h+1 which is exactly log
2
n again
The equality occurring, of course, only when we have only a single node at the bottom levelSlide13
log2
n ≤ h
≤ n-1
Range of Possible Heights, h, for Binary Trees with n Nodes
This is the height of the
maximally “stretched out”
shape we looked at earlier
So when we show that some binary tree operation is O(h), which we can often do rather easily, we’ll know that it’s either O(
lg
n) or O(n) or somewhere in between
Since that can make a pretty big difference in actual performance, the hard work will come in trying to figure out which end we’re at, O(
lg
n) or O(n), and figuring out ways to drive it down towards O(
lg
n)
This is the height of
an almost perfect binary
tree with n nodes, which
shape we know has the
minimum possible height
for
any
binary treeSlide14
Roadmap
V
A
D
P
W
K
C
L
F
T
E
J
M
Binary trees in general
Binary search trees
Definitions and the search (or find) algorithm
Insertion
Deletion
The problem (or why we need AVL trees)
AVL treesSlide15
There’s no obvious rule to tell us where to insert a new node into a binary tree in general
There would seem to be lots of possibilities; we’ll need some additional property that we wish to preserve to help us decide
?
?
Insertion Into a Binary Tree
?
?
?
For our discussion of AVL trees, the binary search tree property is the one we’re interested in
For (somewhat silly) example, if we were trying to preserve a “
zig-zag
” shape property, this spot would be the only place we could insert the next node and still have a
zig-zag
treeSlide16
The key value here…
Binary Search Trees
A binary search tree (or BST) is a binary tree where each node contains some totally ordered* key value and all the nodes obey the BST property: The key values in all the left descendants of a given node are less than the key value of that given node; the key values of its right descendants are greater
H
K
F
M
S
This binary tree is a BST
L
T
F
M
S
Here’s a binary tree with at least one node that does not obey the BST property; so this binary tree is not a BST
*
Values
are totally ordered
iff
, for any two keys
, ,
exacty
one
of three relationships must be true:
< , or = , or >
… causes this node to fail the BST property …
Note that the problem is not between parent and child but between more distant, but still ancestral, relations
—
all
the descendants of a node must have the correct key relationship with it, not just its children
… although this node is happy enoughSlide17
Searching is a fundamental data structure operation and, as we will see, is the first part of the insertion (and deletion) algorithm for a BST as well
Searches are said to terminate successfully or unsuccessfully, depending on whether or not the desired node is found
Start searching at the root of the tree and then loop as follows:If the key we’re searching for matches the key in the current node, we’re done; the search was successful
Else if the key we want is less than the current one we’re looking at,
move down to the left and try again
Else if the key we want is greater than the current one we’re looking at,move down to the right and try again
Else (when we’ve fallen out of the tree), the search was unsuccessful
Performance of the search algorithm: Since we only have to check the key of one node per level, regardless of how many other nodes might be at that same level, the search time is proportional to the number of levels, which is the same as h, the height of the tree; so search time is O(h)
Find
(
K)
Searching a BST to Find Some Node Given a Key
<
M
V
A
D
P
W
K
C
L
F
T
G
E
J
M
K
>J
<
L
=
Find
(
O
)
O
>
M
<
T
<
P
The search for an existing node with a key of ‘K’ is successful
We’ve fallen out of the tree; the search for a node with a key of ‘O’ was unsuccessfulSlide18
Roadmap
V
A
D
P
W
K
C
L
F
T
E
J
M
Binary trees in general
Binary search trees
Definitions and the search (or find) algorithm
Insertion
Deletion
The problem (or why we need AVL trees)
AVL treesSlide19
V
insert
(G)
insert(D)
insert(M)
insert(T)
insert(J)
insert(P)
insert(L)
insert(E)
insert(W)
insert(C)
insert(F)
insert(K)
insert(A)
Simple
Insertion Into a BST
G<J
G>F
insert(V)
Order of Insertions
G<M
A
D
P
W
K
C
L
F
T
G
E
J
M
G
G>E
Insertion into a BST involves searching the tree for the empty place (found by an unsuccessful search) where the new node needs to go if the BST property is to be preserved
The BST above was built by the sequence of insertions shown to the left
Let’s look at the details of the next insertion
The insertion started with a standard search of a binary search tree
The place where the unsuccessful search “fell out of the tree” is where the new node must be inserted so as to preserve the BST property
So insertion, like search, is clearly O(h)Slide20
Roadmap
V
A
D
P
W
K
C
L
F
T
E
J
M
Binary trees in general
Binary search trees
Definitions and the search (or find) algorithm
Insertion
Deletion
The problem (or why we need AVL trees)
AVL treesSlide21
K
Deletion From a Binary Search Tree
V
A
D
P
W
C
L
F
T
E
J
M
Deletion from a BST takes two steps:
Find the node to be deleted using the standard search/find algorithm
Delete it and rebuild the BST as necessary
Nothing new in the first step, so let’s assume we’ve done that and consider the three cases that are needed to cover the second step:
The node to be deleted has no children
The node to be deleted has only one child
The node to be deleted has two childrenSlide22
K
Deletion of a Node With No Children
V
A
D
P
W
C
L
F
T
E
J
M
As a
programming
matter, you’d probably want to have saved that old pointer value somewhere first, before setting it to
NULL
so you could, for example, return unused storage to the operating system via a call to
the
free
function
But as far as the BST itself is concerned, the deletion merely requires setting the correct parent pointer to
NULL
To delete a node with no children, the correct pointer from its parent is just set to
NULL
and poof, the node has been deletedSlide23
descendants
(if any) of
promoted child
k
1
k
2
K
Deletion of a Node With Only One Child
V
A
D
P
W
C
L
T
E
J
M
To delete a node with only one child, the child is “promoted” to replace its deleted parent
parent of deleted node
Note that the BST property is preserved by the promotion: No left or right ancestor-descendant relationships are altered anywhere
Specifically, the now promoted child and all its descendants (if any) remain to the same side of the parent of the now deleted node as they were before the deletion
In this example, node ‘K’ and its descendants were to the right of node ‘J’ before the deletion of node ‘L’ and they are to the right of node ‘J’ after the deletion and their subsequent promotion
only child of node to
be deleted
node to be deleted
All the promoted child’s descendants (if any) move up with it and so will be unaffected by the deletion of one of their ancestors
promoted child
Only one link
needed
to change to delete the desired node and promote its child
Let’s delete node ‘L’Slide24
Deletion of a Node With Two Children
K
V
A
D
P
W
C
L
T
E
J
M
node to be deleted
Let’s look at the case where it comes from the left
– the other case is just the reverse
?
Whichever node we choose to “promote” from here …
… and move up here …
So in order to preserve the BST property here in the left subtree
,
the node we choose to “promote” has to be the one having the largest key value …
… so as to ensure that the BST property holds between the newly promoted node and its left descendents
Once we have found the node to be deleted, we have easy access to its descendants but, unless we’ve done something special, we have no access to its ancestors
(if any
– here, for example, we’ll delete the root)
So what we want to do is replace the data in the node being deleted with data from one of its descendents, so none of the deleted node’s ancestors need to be changed
The question of whom to promote is not as obvious as it was for the case where it just had a single child
There are two choices for where to find the replacement node to promote and either one will actually work just fine
If, for example, we promote node ‘F’, we will have destroyed our BST
– nodes, ‘J’, ‘K’, and ‘L’ are greater than ‘F’ but would be to its left
Either the replacement comes from somewhere on the left of the node being deleted …
… or it comes from somewhere on the right
F
F
… will by the definition of a BST have a key less than that in any node here
J
L
K
So any node from the left of the node we’re deleting will be OK for promotion as far as preserving the BST property with regard to all the nodes on the right of the node being deleted
But how about the promoted node’s relationship with the other nodes still remaining on the left after its promotion?
Deleting a node with 2 children
is going to take some more work
(and some thinking first ;-)Slide25
?
Finding the Largest Node in the Left Sub-tree Is Pretty Simple, Actually
K
V
A
D
P
W
C
F
T
E
J
node being deleted
Move down to the left once (to get to the root of the left subtree) …
L
… which brings us to the node with the largest key value in the left sub-tree of the node to be deleted
node with largest key value in left subtree of node being deleted
… and then slice* down to the right
(to bigger and bigger key values)
until reaching a node with no
right child …
______________________
*
slice: keep moving in the same
direction (down-right
, in this
case)
until
you
can’t go any
farther in that directionSlide26
Oops!
K
V
A
D
P
W
C
F
T
E
J
node just promoted
We just “orphaned” the promoted node’s child!
But this problem will be easier to fix than you might think
LSlide27
Orphans
K
V
A
D
P
W
C
F
T
E
J
node just promoted
L
Q.E.D
L
l
L
r
There would appear to be the standard three possibilities:
There are no orphans; it (node ‘L’) actually had no children (node ‘K’ never existed),
in which case after promoting node ‘L’ we’re all done, the BST property holds everywhere
It had exactly one child, as in the example shown here; in which case the orphaned child itself (node ‘K’)
and its descendants (if any) can
be promoted a single
level,
as we saw on an earlier chart
It (node L) had
two children
(
L
l
to the left and
L
r
to the right) and
we have to go through this whole process all over
again since we just effectively deleted a node with two children!
When will it ever end?
After promotion of the orphan, the BST has been restored
Yucko!
But the
yucko
3
rd
case, two children, can’t happen!
The node just promoted, ‘L’, couldn’t have had two children
(
L
l
and
L
r
)
or it wouldn’t have had the largest key in the
subtree
(
L
r
would be greater) and so it, node ‘L’, wouldn’t have been selected for promotion in the first place
–
node
‘
L
r
’
would have been selected for promotionSlide28
K
Summary of Deletion From a Binary Search Tree
V
A
D
P
W
C
L
F
T
E
J
M
Deletion from a BST takes two steps:
Find the node to be deleted using the standard search/find algorithm
Delete it and rebuild the BST as necessary
Three cases for the second step
The node to be deleted has no children
The node to be deleted has only one child
The node to be deleted has two children
– the BST can be rebuilt by promoting the node with the largest key value from its left subtree or the node with the smallest key value from its right subtree
It’s easy enough to show that all three cases are still O(h) Slide29
Roadmap
V
A
D
P
W
K
C
L
F
T
E
J
M
Binary trees in general
Binary search trees
Definitions and the search (or find) algorithm
Insertion
Deletion
The problem (or why we need AVL trees)
AVL treesSlide30
So What’s the Problem?
An arbitrary series of insertions and deletions can produce a “skinny” BST where h = n-1, leading to a BST for which search and insertion, which are always O(h), are therefore O(n), not the O(lg n) we want
insert(M)insert(T)
insert(W)
insert(V)
V
W
T
M
The problem is that we need the almost perfect shape, or something very similar, with h =
log
2
n
, to get the O(h) performance to be O(lg n)
But our insertion algorithm did not consider shape at all in determining where to insert a new node; so in general, unless we get lucky, we won’t wind up with an almost perfect shape after we do an insertion
“No problem”, you say; first, we’ll do the simple insertion and then afterwards rebuild the almost perfect shape
Unfortunately, the “rebuilding” could easily be
Ω
(n), hardly what we want
This is in fact a real BST, albeit it a “skinny” one that doesn’t look particularly “binaryish”Slide31
And here’s the only possible arrangement of the nodes that ensures the BST property is preserved for the new almost perfect BST
The Almost Perfect Shape is The ProblemIt’s Too Stringent, Too Expensive to Maintain
Here’s an almost perfect binary search tree with n=5 nodes
M
B
H
T
F
C
And here’s the tree after the insertion of a node with the key of ‘C’
It’s still a BST, but it’s no longer almost perfect
After we rebuild to almost perfect shape, it will have to look like this …
M
B
H
T
F
C
… since there’s only one possible shape for an almost perfect binary tree with 6 nodes
Note that every single parent-child relationship had to be changed to restore the BST property, an
Ω
(n) operation at best !Slide32
Conclusions (vis a vis Binary Search trees)
Although BST insertion is O(h) and an almost perfect shape guarantees that h = log2
n, we can’t usually keep the almost perfect shape after a BST insertion without rebuilding, an operation that can often be Ω(n), which surely defeats the goal of making the complete insertion operation itself O(lg n)
The almost perfect shape constraint is the problem; it’s too difficult to maintain — i.e., it usually can’t be done O(lg n)
What we need is an “easier” shape constraint, one that can
always be restored with just O(lg n) operations after an insertionThe shape constraint we’re after is called the “height bounded with differential 1” or
HB(1) property; and it’s what makes AVL trees possibleSlide33
G
Roadmap
V
A
D
P
W
K
C
L
F
T
E
J
M
Binary trees in general
Binary search trees
AVL trees
Definition: An HB(1) binary search tree
O(1) rebalancing to restore the HB(1) property after the BST insertion
Finding the deepest node out of balance in O(h) time
Proof that the HB(1) property means that h is O(lg n)
Some engineering implications of AVL tree propertiesSlide34
G
AVL Trees: BSTs With the HB(1) Property
An AVL tree is a binary search tree in which each node
also
obeys t
he HB(1) property: The heights of its left and right
subtrees must differ by no more than 1Both the BST and HB(1) properties must hold for every node
The tree above is an AVL tree
V
A
D
P
W
K
C
L
F
T
E
J
M
The tree to the right is a BST that is not HB(1) and so is not an AVL tree
M
J
I
L
V
B
W
F
P
R
T
This
node, F,
is not in HB(1) balanceSlide35
G
V
Insertion Into an AVL Tree
A
D
P
W
K
C
L
F
T
E
J
M
Insertion into an AVL tree occurs in two steps:
Do a normal BST insertion so as to preserve the BST property without regard for the HB(1) property
Determine if the BST insertion broke the HB(1) property anywhere, and, if so, fix it somehow while satisfying two constraints:
The
fixing operation
must be O(
lg
n) or better
The fixing operation must
preserve the BST propertySlide36
The AVL tree above was built from an initially empty tree by the sequence of BST insertions shown to the left
This sequence was carefully chosen so that the insertions never broke the HB(1) property anywhereWe won’t always be so lucky; let’s try another insertion
B<M
B<J
V
insert(B)
insert(D)
insert(M)
insert(T)
insert(J)
insert(P)
insert(L)
insert(E)
insert(W)
insert(C)
insert(F)
insert(K)
insert(A)
An HB(1) Breaking
Insertion
Although it naturally preserved the BST property, this
last insertion
destroyed the HB(1) balance of multiple nodes
We’re going to need to restore the HB(1) balance somehow
B<C
insert(V)
Order of Insertions
B<E
A
D
P
W
K
C
L
F
T
B>A
G
E
J
M
B
nodes now
out of balance
J
M
insert(G)Slide37
There are three other similar cases (left-right, right-left, and right-right)
The example here is a
left-left case, one where the destructive insertion occurred under the left subtree of the left child of the deepest node now out of balance
For the left-left case, three subtrees are the key to a re-arrangement that will restore the HB(1) balance to all nodes currently out of balance
without
disturbing the binary search tree property anywhere, thus restoring the AVL tree:
nodes now
out of balance
left child
of deepest node out of balance
old
left sub-tree
of left child of deepest
node out of balance
HB(1) Re-Balancing:
Key Nodes and Subtrees
deepest
node
out of balance
A
D
B
P
W
V
K
G
C
E
J
L
F
T
M
B
J
M
#1
#2
#3
new
left sub-tree of left child of deepest
node out of balance
These three subtrees’ heights always have a fixed relationship to each other that is central to correcting the imbalance induced by the last insertion
last insertion
#2
is the right
subtree
of the left child of the deepest node out of balance
#3
is the right subtree of the deepest node out of balance
#1
is the (new) left subtree of the left child of the deepest node out of balanceSlide38
Height Analysis of the Three Subtrees
subtree
#3
also has height exactly
h
If subtree
#3
had height < h, the deepest node out of balance would have been out of balance before the last insertion
If subtree
#3 had height >
h, the deepest node allegedly out of balance would not, in fact, be out of HB(1) balance at all, and that would be a contradiction
subtree
#2 must be height
h, the same height as subtree #1
was before the last insertion:
If subtree #2 had height
< h, the left child of the allegedly deepest node out of balance would itself be out of HB(1) balance and that would be a contradiction
If subtree
#2 had height
>h, the deepest node out of balance would have been out of HB(1) balance before the last insertion
A
D
K
G
C
E
J
L
F
B
h+1
h
h
h
#1
#2
#3
J
left child
of deepest node out of balance
deepest
node
out of balance
Summary:
In the left-left case,
subtrees
#2 and #3 have to be the same height, which must be exactly one less than the height of
subtree
#1
P
W
V
T
M
M
The last insertion changed the height of
subtree
#1
from
h
to
h+1
, and, in so doing, destroyed the HB(1) balance of one or more of its ancestors
If the height of
subtree
#1
hadn’t changed, no nodes would be out of balance
In this particular example, h=1; but in general, h can be any integer
0, depending on the topology of the tree at the time of the destructive insertion
Reminder:
h can be any integer
0, depending on the shape of the original tree and where the last insertion took placeSlide39
O
nly needed to be changed to achieve the rotation to restore the HB(1) balance for the entire tree
It doesn’t matter if there are a gazillion nodes in subtrees
#1, #2, and #3; it’s still only three
links that need to be changed to restore the HB(1)
property; so the rotation is an O(1) operation
Note that the binary search tree property has been preserved
three links
Re-Balancing the AVL Tree With a Rotation
Because of the fixed relationship among the heights of the three
subtrees, the whole AVL tree can be rebalanced after a left-left case insertion by “rotating”
subtrees #1 and
#3 around subtree #2
P
W
V
T
G
#2
h
F
h+1
A
D
C
E
#1
B
h
K
J
L
#3
J
M
M
h+1Slide40
Each node still has the binary search tree propertyEach node is now again in HB(1) balance
The Rebalanced AVL Tree
P
W
V
K
G
L
T
M
A
D
B
C
E
J
FSlide41
The example showed the rotation for the left-left case –
the insertion that destroyed the HB(1) balance somewhere was at the bottom of the left sub-tree of the left child of the deepest node that wound up out of balanceA right-right case is obviously the mirror image of some left-left caseThe left-right and right-left cases each require two rotations to rebalance the tree, not just one, but each rotation is still a fixed number of steps,
i.e., they’re still O(1)Summary So FarSlide42
After an O(h) BST insertion into an HB(1) binary search tree, the HB(1) balance can be restored while preserving the binary search tree property with at most two
O(1) rotationsDoing the rotation(s) is just O(1), but how do we find the deepest node out of balance, which is the key to the rotation?
So …Slide43
Roadmap
V
A
D
P
W
K
C
L
F
T
E
J
M
Binary trees in general
Binary search trees
AVL trees
Definition: An HB(1) binary search tree
O(1) rebalancing to restore the HB(1) property after the BST insertion
Finding the deepest node out of balance in O(h) time
Proof that the HB(1) property means that h is O(lg n)
Some engineering implications of AVL tree propertiesSlide44
Only nodes that are ancestors of the node just
inserted need to be checked for HB(1) balance after an insertionNothing changed in any subtree of any non-ancestral node ; they were in balance before, so they’re still in balance now
Finding the Deepest Node Out of Balance
B<E
B<C
B>A
B<J
B<M
the stack
the top of the stack is the parent of the node just inserted
here’s the root
of the whole tree
We’ll also need to provide two extra data fields in each node to allow us to keep track of its subtrees’ heights, which we’ll use to determine balance, if and when we insert underneath it
B
A
C
E
J
M
B
M
C
E
J
A
If we push onto a stack the nodes we check on the way down to find the insertion point, we’ll have a data structure that contains the only nodes we need to check for HB(1) balance
Note that the stack, LIFO data structure that it is, has “inverted” the levels of the ancestors — nodes higher in the stack are actually from deeper in the original tree
So the first time we pop the stack and discover an ancestor out of balance, it is the
deepest
node out of balance
0
0
0
0
0
0
0
0
1
2
2
3
3
4
0
1
0
1
2
1
0
0
0
0
1
1
These are the subtree heights from before the last insertion, we’re about to look at the algorithm that adjusts themSlide45
Using the Stack to Process the Ancestors From the Bottom Up
After the insertion, we’ll start popping the stack to access the next ancestor up from the node just inserted and check and adjust its subtree heights as necessary
Whenever we pop a node, we know that it was HB(1) before the last insertion, so there are only two possibilities for the relationship between the heights of its left and right subtrees before the last insertion:
They were equal: or
The ancestor had a short and a long side, differing in height by 1:
The left or right locations of the tall side and the short side of these icons, above, are irrelevant to the concepts here; although they’re relevant to the actual code we’d have to write, all we care about for our conceptual proof here is that the ancestor’s subtree heights were unequal (but obviously differed by only 1)
the stack
M
C
E
J
A
orSlide46
While the Stack Is Not Empty
Pop an ancestor node off the stackCheck the popped node for one of three cases:
Its previously short side grew taller One of its two previously equal sides grew taller
Its previously long side grew taller
the node just inserted
the ancestor just popped off the stack, HB(1) before the last insertion
a subtree prior to the last insertion
A
C
E
J
MSlide47
Case 1: Short-Side Grew Taller
We’re all done: there’s nothing more to be checked or modified. All nodes above this current node retain the HB(1) left and right subtree heights they had before the insertion
Note that the overall height of the tree rooted at the current node has not changed; it was h before; it’s still h now
Ergo: None of the heights of any
subtrees
of any ancestors of the current node have
changed either
h
h-1
current node whose subtree heights are to be examined and updated
We have to record, in the current (just popped) node, a new subtree height for one of its subtrees, since the height of its previously short-side subtree just increased by 1Slide48
Case 2: A Previously Equal Height Subtree Grew Taller
Again, we have to record that the height of one of the subtrees of the current node has just increased by 1
Although the current node remains HB(1), its overall height has increased by 1, so the height of some subtree of its parent has also increased by 1; so we’ll have to continue on up the tree, popping the stack and processing the next ancestor up (the parent of the current node)
If the stack is empty, of course, the current node we’ve just finished processing is the root of the original tree, in which case we’re all done: the last insertion did not destroy the HB(1) balance anywhere and we have correctly updated all affected nodes’ subtree heights
Note that the overall height of the tree rooted at the current node has changed
h+1
h
current node whose subtree heights are to be examined and updatedSlide49
Case 3: Long-Side Grew Taller
Since we built the stack on the way down, as we searched for our insertion point, nodes higher in the stack were deeper in the tree, so the first time we pop a node from the stack and discover that it is out of balance, it is the deepest node out of balance
h
h+1
h+2
this node is now out of balance
Before the last insertion, the difference between the heights of the two subtrees of the current ancestor was 1
After the insertion, the difference between the heights of the subtrees is now 2
deepest
node out of balance
current node whose subtree heights are to be examined and updated
Slide50
Case 3: Long-Side Grew Taller (cont’d)
P
W
V
T
G
#2
F
K
J
L
#3
J
M
M
A
D
C
E
#1
B
And the deepest node out of balance is the only one we care about!
We don’t need to continue to look for other
nodes out of balance farther up the tree: Even if such nodes exist, the rotation we’re about to do with the just identified deepest node out of balance will restore the balance for any higher out of balance nodes as well,
and
leave their old values for their subtree heights correct and unchanged
deepest node out of balance
out of balance ancestor to deepest node out of balance
last insertion
4 3
But after the rotation, this height for the left subtree is correct again
Since neither of the subtree heights for this temporarily out of balance node had to be changed, nothing needs to be checked or changed in any of its ancestors (if any) either
So once we do the rotation, we’re all done;
the tree is rebalanced and each node’s recorded subtree heights are correct
P
W
V
K
G
L
T
M
A
D
B
C
E
J
F
Before the last insertion (that destroyed its balance), the height of the left subtree of this node was 4, which is no longer the caseSlide51
Summary of AVL Trees So Far
The search of, and simple BST insertion into, an AVL tree are, for all practical purposes, the same algorithm, the standard BST search/insertion algorithm, which is O(h)
Since we only check one node at each level during the insertion, the depth of the stack we use to hold nodes whose subtree heights need to be checked will never exceed the height of the original tree, so adjusting the subtree heights and finding the deepest node out of balance (if any) will be O(h)
Once we find the deepest node out of balance, doing the necessary rotation(s) to restore the HB(1) balance is just
O(1)
Overall, we know that search, insertion (including re-balancing), and deletion* are all O(h)
---------------
* The analysis for deletion is slightly more complex, but the end result is the same
– O(h)Slide52
Next Step
We need to know the mathematical relationship between
n and h induced by the HB(1) property to determine the “real” O-notation for AVL tree operations
We know they’re all O(h), of course, but what we want is a function
f(
n) that provides an upper bound for h for the maximum, or worst case, height of an HB(1) tree, in terms of n, the number of nodes; then we’d know that AVL tree operations were O(
f
(n)
)For almost perfect binary trees, for example, the almost perfect shape forces h ≤ log
2(n)
HB(1) trees may not be quite that good , but as long as the upper bound is still O(
lg n), we’ll be happySlide53
Roadmap
Binary trees in general
Binary search trees
AVL trees
Definition: An HB(1) binary search treeO(1) rebalancing to restore the HB(1) property after the BST insertion
Finding the deepest node out of balance in O(h) time
Proof that the HB(1) property means that h is O(lg n)
Some engineering implications of AVL tree properties
V
A
D
P
W
K
C
L
F
T
E
J
MSlide54
What’s the Worst Case Height for an HB(1) Tree as a Function of Its Number of Nodes?
We’re looking for an upper bound on h, the worst case, the stringiest, most stretched out AVL tree possible,
having the maximum height for its number of nodes, nWe know that with no shape constraints at all, all we can say is that
h
≤
n-1, which means operations on shape unconstrained binary search trees could be O(n) We know that for an almost perfect binary tree, h =
log
2n
, so h ≤
log2n, but
we also know that only the search operation is O(h) for an almost perfect tree; rebuilding the almost perfect shape after an insertion (or deletion) could be
Ω(n), which is why we’re looking at the HB(1) property
We hope that the HB(1) constraint will allow us to do better than
h ≤
n-1, even if it’s not as good as the almost perfect
h ≤
log2n
itself
We don’t need an exact equation (one exists, but the math is tougher); as long as h
< c
·log2
n for some constant c, we’ll be happy; since h will still be O(lg n) and all our O(h) AVL operations will therefore be O(
lg n)
So h
< c
·log
2n for HB(1) trees is what we hope to proveSlide55
Outline of the Proof
First, the longest part, we’ll derive a lower bound, call it m(h), for the
minimum number of nodes in an HB(1) tree as a function of its height, h, so that we know for any HB(1) tree of height h, n m(h)
Once we have an
m(h) for the minimum number of nodes, we’ll just apply its inverse, m
-1, to both sides of the inequality, giving us m-1
(n)
m-1
(m(h)), or m
-1(n)
h
, which tells us that
h ≤ m
-1(n), which is the upper bound on the height that we’re really after
We’ve already seen this notion of “inverse” function
For ordinary binary trees, for example, n
h+1 and therefore h
≤
n-1, since adding 1 and subtracting 1 are inverse operations
Since exponentiation and logarithm are inverse functions
and we want m-1
(n) to be c
·log2
n, look for an exponential function of h in the n
m(h) lower bound for the number of nodes — when we see that, we’ll be very close to the end of our proof
We already know that all our AVL operations are O(h), so once we get
h ≤ m
-1(n), we’ll know AVL operations are O(m
-1(n))Slide56
n=m(h), the Worst Case for an HB(1) Tree
Define m(h) as the minimum number of nodes for an HB(1) tree of height hIf an HB(1) tree has fewer than m(h) nodes, it must have height
< hConversely, h is the maximum height for an HB(1) tree with m(h) nodes; if its height is greater than h, it has to have n >
m(h) nodes
For comparison purposes, consider a similar mu(h) for totally unconstrained binary trees, where, for example, mu(3)=
4An ordinary binary tree of height 3 must have at least 4 nodes; if it has fewer than 4 nodes, it can’t have height 3; its height must
be less than thatContra wise, with 4 nodes, it can’t get any taller than h=3; if it has h
> 3, it has to have more than 4 nodesSlide57
There’s no way to eliminate any node (to reduce n from 7 to 6) and still keep this tree an HB(1) tree of height 3
Remove an interior node and it’s not even a binary tree any moreLet’s look at trying to eliminate some node
Illustration of an m(3) HB(1) Tree
Here’s an HB(1) tree with n=7 nodes and height h=3
leaf
Contra wise, there’s no way to rearrange 7 nodes to gain extra height and still keep every node HB(1)
n=7 is the minimum possible number of nodes for an HB(1) tree of height 3 (proof by animated example ;-)
This tree is as “stringy” as the HB(1) property will let it be
n=7 is the minimum number of nodes for an HB(1) tree with h=3
h=3 is the maximum (worst case) height for an HB(1) tree with n=7
To keep n=7 but increase the height, some existing node would have to be moved to a new level underneath this currently deepest node
Again, moving an interior node destroys the binary tree completely so let’s look only at the other leaves
So for HB(1) trees,
m(3)
=
7
… and this node becomes out of balance
… and this node becomes out of balance
… and
three
nodes become out of balance
… and the same three nodes become out of balance again
Remove this leaf …
Remove this leaf …
Remove this leaf …
… and although the tree is still HB(1), it no longer has height 3
Move this leaf …
Try moving this leaf instead …Slide58
The HB(1) “Spring”
The HB(1) property is thus like a spring, that resists being stretched too far
Without the spring, we could “stretch” 7 nodes out to a worst case height of 6
But the HB(1) spring will prevent any attempt to stretch 7 nodes out beyond a height of 3
We can add more nodes to this HB(1) tree with m(3) nodes, but until we’ve added enough to get to n
≥
m(4), there’s still no way to get it to stretch out to h
=
4 while remaining HB(1)
Now we need to know quantitatively just how strong the HB(1) spring is: As a function of n, how small can it keep h so that m(h)
≤
n
<
m(h+1)?
In other words, not just for n
=
m(h), but
for
m(h)
≤
n
<
m(h+1),
h is the greatest possible height for an HB(1) tree of n nodes
n is still < m(4)Slide59
Could an HB(1) tree of height h with the minimum, i.e., n = m(h), nodes have two equal height subtrees (of height h-1 each) ?
Clearly not, since we could lop off all the nodes at the bottom level of one of the subtrees and still have an HB(1) tree of overall height h but with fewer nodes than before
– so for the original tree, with equal height subtrees, n could
not
have been the minimum possible number of nodes
Relationship Between the Subtrees
in an m(h) HB(1) Tree
h-2
h
h-1Slide60
The Recurrence Relationship for m(h)
So an HB(1) tree of height h with the minimum, i.e., m(h)
, nodes must have a long side and a short side, of height of height h-1 and h-2, respectively; and again we don’t care which side is taller or shorter, so let’s just look at this case:
h
So an HB(1) tree of height h with the minimum number of nodes consists of a root with m(h-1) nodes in one subtree and m(h-2) in the other; so
m(h)
= 1 + m(h-1) + m(h-2)
How many nodes in this subtree?
Well, it’s got to be an HB(1) tree in its own right, of course, and if the overall tree here is to have the absolute minimum possible number of nodes, so too must this subtree of height h-1, so it must contain only m(h-1) nodes …
… similarly, this subtree must contains only m(h-2) nodes
m(h-2)
h-1
m(h-1)
h-2Slide61
Let n be the number of nodes in an HB(1) tree of height h, where h is an even number*, then
n ≥
m(h) ≥ 1 + m(h-1) + m(h-2)
≥
1 + 2•m(h-2)
≥ 1 + 2
•(1 + 2m(h-4))
≥ 1 + 2 + 22
m(h-4)
≥ 1 + 2 + 22
+ 23m(h-6)
≥ 1 + 2 + 22 + 2
3 + ... +
2k m(h-2k)
≥
1 + 2 + 22 + 23
+ ... + 2
k + ... +2h/2
m(h-2(h/2))≥
1 + 2 + 22 + 23
+ ... + 2
k + ... +2h/2 m(0)
≥
1 + 2 + 22 + 2
3 + ... + 2
k + ... +2h/2
• 1
≥
≥ 2
(h/2) +
1 -1
Lower Bound for n as a Function of h
… since we’ve reached m(0)
* the odd number case is slightly more complicated but it doesn't alter the final result
–
trust me (or do the math yourself ;-)
h/2
∑ 2ii=0
m(h-1) > m(h-2), since the minimum number of nodes for a tree of height h-1 must be greater than the minimum number of nodes for a (shorter) tree of height h-2
… and
so on
…
And here’s the exponential lower bound for n as a function of h that we hoped we’d find
!
I.e., the minimum number of nodes in an AVL tree grows exponentially as the height of the tree increases
… and
m(h-4)
≥
1+ 2m(h-6)
Just as m(h)
≥
1+2
m(h-2)
so too is
m(h-2)
≥
1+2
m(h-4)
… which we know is 1, since the minimum number of nodes in a tree of height 0 is one
… until we can’t go any further …
Substituting the recurrence equation we just derived for m(h)Slide62
For any HB(1) tree with n nodes and height h, we know that n
≥ m(h) = 2h/2 +1 -1
The Inverse of the Lower Bound For n Gives Us an Upper Bound on h
2
h/2 +1 ≤ n+1
2
h/2 +1 -1 ≤ n
h/2
≤ log2(n+1) - 1
h/2 +1
≤ log2(n+1)
h
≤ 2∙log2(n+1) - 2
To solve for h, we take the binary logarithm of both sides, which is the inverse function of the exponentiation we currently see here …
Q.E.D.
h
is O(lg n)
n
≥ 2h/2 +1 -1
… which gets us this
Just swapping the left and right sides
(and remembering to reverse the inequality ;-)Slide63
We’re Done! (Almost ;-)
Since the AVL tree operations we looked at were all O(h) and we now know that h is O(lg n), we have our dynamic data structure, the HB(1) binary search tree, or AVL tree, which can be searched, inserted into, and deleted from, all in O(lg n) timeSlide64
Roadmap
Binary trees in general
Binary search trees
AVL trees
Definition: An HB(1) binary search tree
O(1) rebalancing to restore the HB(1) property after the BST insertionFinding the deepest node out of balance in O(h) time
Proof that the HB(1) property means that h is O(lg
n)
Some engineering implications of AVL tree
properties
V
A
D
P
W
K
C
L
F
T
E
J
MSlide65
Small Ratio Between Worst and Best Case Performance for AVL Trees
Since we’ve just proved that for an HB(1) tree h
≤ 2∙log2(n+1) –
2, even in the worst case an HB(1) tree will never be more than twice the height of a best case HB(1) tree with the same number of nodes, namely
log
2n
It’s actually possible to get a tighter upper bound for the height of an HB(1) tree and show that h
< 1.44
…· log
2n
+ c, so in reality the worst case height penalty for relaxing the almost perfect shape constraint to an HB(1) constraint is under 45%, but:
The math to prove the tighter bound is more complex than what we did here (think Fibonacci numbers and the golden ratio)
From the standpoint of complexity classes, there’s no real point to the extra work; O(lg
n) is O(lg n), the constants don’t matter
But remember the tighter upper bound (1.44… ) and let’s look at the relationship between height and number of nodes in tabular numeric form and see what it means for software systems engineeringSlide66
Worst and Best Case HB(1) Trees
Minimum and Maximum Nodes for a Given Height
height h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
n = h+1
1
2
4
7
12
20
33
54
88
143
232
376
609
986
1596
2583
4180
6764
10,945
m(h)=1+m(h-1)+m(h-2)
# of nodes for an HB(1) tree
# of nodes for a binary tree with no shape constraint
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
h
min max
1
3
7
15
31
63
127
255
511
1023
2047
4095
8191
16, 383
32,767
65,535
131,071
262,143
524,287
n = 2
h+1
-1
1
3
7
15
31
63
127
255
511
1023
2047
4095
8191
16, 383
32,767
65,535
131,071
262,143
524,287
n = 2
h+1
-1
min max
This is the recursion relationship we derived earlier…
Since a perfect binary tree is also HB(1), it is also the max for HB(1) trees
This is the number of nodes in a perfect binary tree that we derived earlier, the maximum for
any
binary tree
Remember:
Since many binary tree algorithms are O(h), we want our trees to be very “bushy”, lots of nodes in as little height as possible
Contra wise, our worst case is when a tree is “strung out” to have the minimum number of nodes possible for its height
But for an HB(1) tree, even in worst case the minimums still grow exponentially
Our old friend the HB(1) spring keeps the tree from getting very strung out, forcing it to have lots of nodes in relationship to its height — not as many as a perfect binary tree, as in the maximum case to the right, but lots, nonetheless; many more than if there were no HB(1) constraint
Compare the minimum of n=10,945 for an HB(1) tree of h=18 with an unconstrained tree’s n=19
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
This skinniest of all possible HB(1) trees of
height
18
is still pretty bushy
Not as bushy as an almost perfect binary tree, but
much
bushier than the skinniest binary tree with no shape constraints whatsoever
… so it’s a simple, if repetitive, matter of addition to fill in these HB(1) minimums starting from the two obvious cases for h=0 and h=1:
h=0, n=1
or
h=1, n=2
Without a shape constraint, the
worst case is pretty stringy indeed,
not really very tree-like at allSlide67
•
•
•
•
•
•
•
•
•
•
•
•
Let’s turn the numbers around so as to highlight the range of possible heights an HB(1) tree can have for a given number of nodes
Let’s look at how the range of heights varies as the number of nodes increases by factors of 10
3
—3
6
—6
9
—9
13
—13
log
2
n
range of heights for an almost perfect binary tree
unconstrained binary tree
HB(1) tree
min h max h
min h max h
3
—
9
6
—
99
9
—
999
13
—
9999
log
2
n
—
n
-
1
# of nodes, n
3
—
3
6
—
8
9
—
13
13
—
17
range of possible heights
10
100
1000
10,000
n
The Range of Possible Heights for HB(1) Trees
(and Why We Care)
We’re looking, in this example, for the maximum (worst case) height for an HB(1) tree with n=10,000 nodes …
These minimum heights …
It’s pretty easy to see where most of these numbers come from
These minimums …
… also come from here, since an almost perfect binary tree is also an HB(1) tree and so has the minimum height for an HB(1) tree
Data structures whose best case performance is fantastic but whose worst case performance, even if unlikely, is really awful usually can’t be used in real-time systems, which certainly includes systems with a significant amount of human-computer interaction
Since AVL trees not only offer really good, O(
lg
n), performance, but they do so with very little variation between best case and worst case, they are an important asset for systems engineers concerned with consistently predictable systems performance
But, as noted earlier (although we didn’t prove it), the worst case height of an HB(1) tree is
always
less than 45% greater than its best case; so an AVL tree will always provide pretty close to its optimum performance, regardless of its topology or how many nodes it contains
… so the worst case for an HB(1) tree with 10,000 nodes must be h=17, not h=18; the HB(1) spring won’t let us stretch 10,000 nodes out to a height of 18 and still have an HB(1) tree
height h
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
17
Note that n=10,000 is between the two entries for heights 17 and 18
The HB(1) spring is doing its job;
HB(1) trees always stay nice and bushy, lots of nodes crammed into not much more than the bare minimum height
minimum # of nodes for an AVL tree of height h
1
2
4
7
12
20
33
54
88
143
232
376
609
986
1596
2583
4180
6764
10945
Now if an HB(1) tree with 10,000 nodes could get stretched out to have a height of h=18 and still remain HB(1), then 10,945 would
not
be the minimum number of nodes for an HB(1) tree with h=18, which would contradict this table …
There
is
an exact formula; but it’s complicated and so is its derivation. Instead, let’s just do some thinking based on an extract from the table
we developed on the previous chart.
But where do the maximum HB(1) heights like this 17 come from?
… come from here, since an almost perfect binary tree, having a unique shape, has only one height for a given number of nodes and it is the minimum possible height for
any
binary tree with that number of nodes
We’re looking at how the range of possible heights for an HB(1) tree changes as we increase the number of nodes in the tree
10945
These maximums come
from the super stretched
out shape with only 1 node
per level so that h
=
n-1
Note that the range of possible heights for unconstrained binary trees gets to be enormous since the ratio between worst case and best case performance, (n-1)
/
log
2
n
,
is unbounded, growing arbitrarily large as the number of nodes increases
So if Google used ordinary binary trees, some
queries would be answered
in seconds while other
queries could
take hours, or even yearsSlide68
Now We’re Done!
Having shown that binary trees, particularly AVL trees, are the most beautiful data structures in the universe – and practical too, although I doubt that they are much used by Google, for which there are actually even better structures available (not as beautiful though ;-) but AVL trees are certainly heavily used in lots of other places