AVL Trees
An AVL tree is the first balanced BST: at every node the two subtrees' heights differ by at most . A Fibonacci-style minimal-node argument forces height $h \le 1.
╌╌╌╌
The previous lesson left us with a binary search tree that does everything in time: fast when the tree is bushy, when a run of sorted insertions stretches it into a height- path. The fix is to prevent the tree from getting tall: pick a structural invariant that pins height to , and restore it after every update. The AVL tree, named for Adelson-Velsky and Landis (1962), is the oldest such scheme and the easiest to reason about, balancing by a direct height constraint at every node.1
To talk about rebalancing we need one primitive, which the next lesson on balanced search trees treats in full: the rotation. A rotation rearranges three pointers to change a subtree's shape, and so its height, while preserving the BST ordering and running in time. A right rotation at lifts its left child to the root and makes the right child of ; a left rotation is the inverse. That is all we need here: a cheap, order-preserving operation that trades height between siblings.
The AVL invariant
Define the height of a node as the number of edges on the longest downward path to a leaf, with . The balance factor is
and the invariant says exactly for every node. We store (or, equivalently, ) in each node and keep it current as the tree changes; both a search and an in-order walk ignore the field entirely, so a read-only operation on an AVL tree is just a BST operation.
A node with is left-heavy past tolerance, right-heavy; these are the two illegal states an update can create, and the two we must repair.
Height is logarithmic
The invariant forces a logarithmic height bound. The cleanest argument is extremal: ask how few nodes an AVL tree of a given height can possibly contain. A sparse tree is the dangerous case, so if even the sparsest legal tree is bushy, all of them are.
The recurrence is easiest to believe by drawing it. Each minimal tree is a root whose children are the two previous minimal trees — the same doubling-back structure as the Fibonacci numbers themselves:
The minimal-node trees are the Fibonacci trees: the sparsest height- AVL tree is a root over a Fibonacci tree of height and one of height . Because , an AVL tree is provably shorter than the worst-case red-black tree of the same size, so its lookups touch fewer nodes. With guaranteed, search, , , , and successor all run in worst-case time.3
Insertion: rebalancing on the way up
We insert a key exactly as in a plain BST: descend to a leaf position and attach the new node. That can only push heights up along the single root-to-leaf path we just walked, so we retrace it upward, recomputing at each node. Let be the lowest node whose balance factor has become . Its imbalance was caused by the new node landing in one of four positions relative to , named by the two steps down the heavy path from toward the insertion:
- LL: left child left-heavy, a single right rotation at .
- RR: right child right-heavy, a single left rotation at .
- LR: left child right-heavy, a left rotation at the child, then a right rotation at .
- RL: right child left-heavy, a right rotation at the child, then a left rotation at .
Consider the LL case. Node has balance , its left child leans left, and the new node sits under 's left child . A single right rotation at lifts into 's place, hangs as 's right child, and rehomes 's old right subtree as 's new left subtree.
The height bookkeeping makes the repair exact. Measure heights at the moment of violation: say and have height , and 's subtree has height because it contains the new node. Then , and 's two subtrees have heights and : balance , the violation. After the right rotation, roots and (both height ), so has height and balance ; roots (height ) and (height ), so has height and balance . Before the insertion, 's height was — exactly the height has now. The subtree presents the same height to its parent as before the insert, so no ancestor's balance factor changes, and the repair is complete.
The RR case is the exact mirror: has balance , its right child leans right, and the new node sits under 's right child . A single left rotation at lifts , hangs as 's left child, and rehomes 's old left subtree as 's new right subtree. The same bookkeeping applies with left and right exchanged.
The LR case cannot be fixed by a single rotation: the heavy path zig-zags, so we first rotate the child to straighten it into an LL shape, then finish with the right rotation at . Here has balance , its left child leans right, and the offending grandchild is 's right child. A left rotation at lifts above ; the subtree is now left-left-heavy, and a right rotation at completes the repair, leaving as the new root.
The bookkeeping for LR: at the violation, and have height , and 's subtree has height — its children and have heights and in some order, whichever one received the new node. So has height and is at balance . After the double rotation, is the root; its left child roots (height ) and (height ), so ; its right child roots (height ) and (height ), so . Both have balance or , legal, and 's height is , again exactly 's pre-insert height, so the violation cannot propagate. One subtlety worth noticing: after an LR repair, exactly one of ends up with balance (whichever lost the shorter of ), and ends at balance .
The RL case is the mirror of LR — the heavy path zig-zags right-then-left, so we straighten with a right rotation at the child before the left rotation at :
In every case the rebalanced subtree ends up with the same height it had before the insertion, which is the decisive fact:
So insertion is to descend, to walk back up adjusting heights, and at most a double rotation ( rotations) to repair: overall. The dispatch is driven entirely by the stored heights:
- 1
- 2while do
- 3
- 4balance factor of
- 5if thenleft-heavy: LL or LR
- 6if then
- 7LL
- 8else
- 9;LR
- 10breakheight restored, ancestors safe
- 11else if thenright-heavy: RR or RL
- 12if then
- 13RR
- 14else
- 15;RL
- 16break
- 17
A worked insertion sequence
Insert the keys into an empty AVL tree, in that order. This sequence is the sorted-order input that destroys a plain BST, plus one out-of-order key at the end to force a double rotation.
- Insert 10, 20. becomes the root; its right child. Heights: , , balance factors and . Legal.
- Insert 30. It lands as 's right child. Retracing: , fine; but . The lowest violation is , its right child leans right: RR. One left rotation at gives as root with children and , all balance factors , and stops.
- Insert 40. Path , attach right. Retracing: , . No violation, no rotation.
- Insert 50. Path , attach right. Retracing: , then — the lowest violation is , not the root. Its right child leans right: RR again. A left rotation at yields the subtree over and ; the tree is now over and , and is legal, so retracing stops.
- Insert 25. Path , attach as 's left child. Retracing: , fine; with , fine; . Violation at , and this time its right child leans left: the zig-zag RL case, with and . First a right rotation at straightens the path ( lifts above ), then a left rotation at lifts to the root.
Two properties show in this trace. Repairs fire rarely — six inserts triggered three, four rotations in all — and each fires at the lowest violated node only, never higher, because the repair restores the subtree's pre-insert height. And the sorted prefix , which would have built a height- path in a plain BST, ends up at height : the tree handles adversarial order at rotations per insert.
Deletion: the same cases, but up the whole path
Deletion starts as in a BST, splicing out the node, or its in-order successor if it has two children, then retraces the path to the root updating heights, applying exactly the same four rotation cases at any node that reaches . The one difference is consequential. A rotation that repairs an insertion preserves the subtree's height, but a rotation that repairs a deletion can shrink the subtree by one. That shorter subtree may unbalance the node's parent, which may unbalance its parent, and so on. Deletion can therefore trigger up to rotations cascading toward the root, though each is still , so the operation remains .3
The asymmetry has a precise cause. An insertion grows the taller side, and the rotation cuts it back to exactly the old height, so no ancestor's balance changes. A deletion shrinks a side, and a rotation can only redistribute height, not create it: when the rotation at finishes, the repaired subtree often stands one shorter than before the delete, and the parent must re-check its own balance against a subtree that genuinely changed size. The retracing loop stops early in exactly two situations: at a node whose balance factor moves from to (one subtree shrank, but the node's height is set by the other and is unchanged), or after a rotation in which the lifted child had balance (that rotation preserves the subtree's height). Otherwise the height drop keeps propagating.
Concretely, take the sparsest height- AVL tree on the keys arranged as over and , and delete . Node becomes a leaf, legal by itself, but at the balance is now . The left child leans left (), so this is LL: one right rotation at . The result, over and , is a legal AVL tree of height — one shorter than the original. A single leaf deletion shrank the whole tree, and if this tree were itself a subtree, the shrink would arrive at its parent exactly as in the schematic above. Fibonacci trees realize the worst case: every node is already at balance , so a deletion on the short side of each ancestor can force a rotation at every level, of them.
AVL versus red-black
AVL and red-black trees both guarantee height, but they sit at opposite ends of a tradeoff. The AVL height-difference invariant is strict: , noticeably shorter than red-black's , so AVL lookups are faster, the structure of choice for read-heavy workloads. The cost falls on updates: AVL trees track exact heights and may rotate to repair even small imbalances, whereas red-black trees tolerate looser balance and rely on cheap recolorings, doing fewer rotations per update. Roughly: AVL is more rigidly balanced and faster to search; red-black is cheaper to mutate, which is why it backs most standard-library ordered maps.4
The balance spectrum
The AVL tree (Adelson-Velsky and Landis, 1962) was the first self-balancing
binary search tree, and its height-difference idea led to a family of variants
that trade the strictness of differ by at most
for cheaper maintenance.
Relaxing the balance factor. Allow subtree heights to differ by up to instead of and you get -balanced or HB() trees: taller, so lookups touch a few more nodes, but rebalanced less often. Pushing the same idea the other way, weak AVL (WAVL) trees (Haeupler, Sen, and Tarjan, 2015) use a rank rule that interpolates between AVL and red-black, an untouched WAVL tree is as short as an AVL tree, but after deletions it degrades gracefully toward red-black balance, doing at most one rotation per deletion where an AVL tree can cascade. WAVL is a clean answer to exactly the AVL-vs-red-black tension this lesson closes on: it aims for AVL's short trees with red-black's cheap deletes.
Why the four cases are really two. The LL/RR/LR/RL taxonomy is a special case
of a general fact: any single imbalance is fixable by one or two rotations, and
the double cases (LR, RL) are just rotate the child to reduce to a single case, then rotate the parent.
The same double-rotation appears verbatim in red-black
insert-fixup's Case 2-then-3, which is no coincidence: both are the standard way
to straighten a zig-zag
before a zig-zig.
Where AVL wins today. Because AVL trees are the shortest of the common balanced BSTs, they remain the pick for in-memory indexes and language runtimes whose workloads are lookup-dominated, some database in-memory indexes and the Linux kernel's earlier scheduler used AVL-style structures. When updates dominate, red-black or WAVL win; when the data lives on disk, neither, the fan-out of a B-tree beats any binary tree.5
Takeaways
- An AVL tree is a BST with the invariant that every node's two subtrees differ in height by at most , i.e. its balance factor ; each node stores its height (or balance).
- A minimal-node / Fibonacci-tree argument gives , so and height , hence all operations are worst-case .
- Insertion descends as a BST, retraces the path updating heights, and repairs the lowest unbalanced node with one of four cases, LL (right), RR (left), LR (left-then-right), RL (right-then-left), using rotations, because the fix restores the subtree's prior height.
- Deletion uses the same four cases but its rotations can shrink a subtree, so the rebalancing may cascade up to the root, taking rotations.
- Versus red-black trees: AVL is more rigidly balanced (shorter, faster lookups) but does more rotations per update.
Footnotes
- Erickson, Ch. — Balanced Binary Search Trees: the height-balance invariant and its restoration by rotation after each update. ↩
- CLRS, Problem 13-3 — AVL Trees: the Fibonacci minimal-node recurrence and the height bound; insertion via with rotations. ↩
- Skiena, §3.4 — Balanced Search Trees: AVL operations are ; deletion may rebalance along the full root path. ↩ ↩2
- Skiena, §3.4 — Balanced Search Trees: the AVL-vs-red-black tradeoff — tighter balance and faster search versus cheaper update. ↩
- Adelson-Velsky & Landis,
An algorithm for the organization of information
(1962), the original AVL tree; Haeupler, Sen & Tarjan,Rank-balanced trees
(WAVL, 2015), interpolating between AVL and red-black balance. ↩
╌╌ END ╌╌