The guarantee, up to a million
In step 1 you wrote down a guess: what will the height be at a million records, with strictly ascending input?
$ go test -run AVLHeightGrowth -v
n height log2 n h/log2n cmps/lookup rot/insert
1000 10 10.0 1.00 8.987 0.990
10000 14 13.3 1.05 12.363 0.999
100000 17 16.6 1.02 15.689 1.000
1000000 20 19.9 1.00 18.951 1.000
20.
A million records, the worst possible insertion order, and any title is found in 19 comparisons.
The h/log2n column
1.00 1.05 1.02 1.00
Not "roughly logarithmic". The height is log2(n), rounded.
Compare with the same column in lesson 11, where the BST was being fed shuffled — favourable — input:
| h ÷ log2 n | |
|---|---|
| BST, shuffled input (lesson 11) | 1.97 – 2.47 |
| AVL, sorted input (lesson 12) | 1.00 – 1.05 |
The AVL tree at its worst is about half as deep as the BST at its realistic best.
And it holds for any order
Lesson 11's homework asked for a third worst-case order — neither ascending nor
descending. The answer was a zigzag: take alternately from the two ends of what
remains. It also produced height n.
n = 20000, bound 20.3
ascending height 15 0.999 rotations per insert
descending height 15 0.999 rotations per insert
zigzag height 18 1.623 rotations per insert
The zigzag is the most expensive of the three: 1.62 rotations per insertion instead of 1.0, and a tree three levels taller. And still comfortably under the bound.
That is what the word "guarantee" means. Not "it worked for the inputs we tried" but "there is no input for which it fails" — because the bound follows from an invariant that every node checks for itself.
What changed since lesson 11
Lesson 11's step 8 listed four requirements. Put them beside what you have:
| requirement | met? |
|---|---|
| the tree rearranges itself during insertion | yes — rebalance on the way back up |
the rearrangement costs O(log n), not O(n) |
yes — one check per node on the path |
| the BST invariant survives | yes — TestRotationsPreserveTheOrdering |
the height stays O(log n) guaranteed |
yes — the bound, checked by a test |
Which means lesson 11's test now has to fail. It does:
TestSortedInsertDegeneratesIntoAList requires Height() == n, and this tree
gives 14. Breaking that test was the point of this lesson.