Don't like this style? Click here to change it! blue.css
Most of the operations that we care about in a binary search tree have \(\mathcal{O(h)}\) complexity. The goal of a balanced binary search tree is to keep \(h = \mathcal{O}(\log{n})\).
I'll start with two approaches for perfectly balancing any BST. Just to be clear my goal is to go from something like this:
To something like this:
Pretty simple idea. Put the data into an array, sort it, and make the middle element the root of a new BST (recurse to make the root of the left and right childten).
Trace Task 1: Take the above unbalanced BST. Write down the numbers in order. Sketch the balanced BST which is mild from this middle-root idea.
Complexity Task 2: Given a bad BST what is the worst case complexity of this approach? What happens when you add new elements? How much space/memory does this approach take?
This is a neat idea (which is the heart of today's lecture) for shifting the balance of power at a node. We can use a rotation to preserve the Binary Search Tree property but shift (in constant time) some height from the left subtree to the right subtree at a node.
Warm-up Task 3: Take a look at this image and sort the following nodes in part
(a), then again in part (b): Q, Ch, Gr, Par, R, P
So the image we just analyzed is a right rotation at the node Par
. It is
basically a swap that preserves the Binary Search Tree Property.
The mechanics of it are that the grandparent will have it's right child point to the child node. The child node will have its right child become the parent node. And the parent will have it's left child become the child's right child.
This next task let us watch a rotation take place.
Many of our data structures are property-based. That is, we take a normal construct like an array or linked-list then toss in a defining characteristic that we want. That constraint dictates how we do the standard actions (insert, remove, find).
An AVL tree is no different, the magic property to work with is: the height of the left and right subtree cannot differ by more than 1.
To see that this property is enough to give us a balanced BST think about the following:
The fewest number of nodes that a height \(h\) AVL tree can have (\(n_h\)) is at least \(n_{h-1} + n_{h-2} + 1\). (By the way this is also called the Leonardo sequence.)
Conceptual Task 8: How fast does the fibonacci sequence grow asymptotically? Is the size of \(n_h\) larger or smaller than the \(h\)th Fibonacci number?
So just like the other property-preserving data structures an AVL tree needs to have a special insert and a special remove to maintain its nearly equal height child policy.
In our case we can do the normal BST insertion/removal followed by a rebalancing at any place which has a 2 or -2 (it can't be worse than that).
For rebalancing there are four cases to deal with (conceptually two) I lean left and my child leans left (LL), I lean left and my child leans rigth (LR). (The other two are RR, RL.)