There is no deletion here, and what that costs
avl.go has no Delete. That is a decision, not a hole, and it is worth
saying what it costs.
What writing it would involve
Deleting from an AVL tree is lesson 11's second drill (leaf / one child / two
children via the successor), followed by rebalance on the way back up.
Implemented and measured:
after 10,000 deletions from 20,000: len 10000, height 14 (bound 18.8), 4997 rotations
It works. The bound holds. The ordering survives.
How much code:
| lines (excluding comments and blanks) | |
|---|---|
Put |
21 |
Delete |
40 |
The tree's mutation code goes from 21 lines to 61 — roughly triple.
And what you would learn from it
Nothing.
The rotations are the same four. rebalance is the same function, untouched.
The invariant is the same. The bound is the same.
Only two things are new, and both are bookkeeping rather than an idea:
- when deleting a node with two children, the path to repair is the successor's, not the deleted node's;
- an insertion needs at most one repair point, after which the heights stop changing; a deletion can cascade repairs all the way to the root.
The second is the only real difference and it fits in one sentence. Paying forty lines and half a lesson for it is a bad trade.
This lesson's idea is an invariant that bounds the height, and you have it already. Deletion applies the same idea in one more place.
So deletion is a coursework option rather than a step. Anyone who wants it has
everything needed: the rotations, rebalance, the bound, and a test that will say
whether it worked.
Where trees like this actually live
Briefly, because it was checked rather than guessed.
transit has no balanced tree — lesson 11 enumerated every type in the
repository and there is no tree of any kind. Nor does it need one: its indexes are
built once and never modified, and in that case a sorted slice with a binary
search is perfectly balanced for free.
Nor does Go's standard library. The entire container package is:
container/heap container/list container/ring
A heap, a doubly linked list and a ring. No tree. Go's answer for an ordered set
is different — sort a slice and use sort.Search, the same lowerBound you wrote
in lesson 6.
That does not mean balanced trees are unnecessary. It means they live where the
data keeps changing and has to stay ordered — database indexes, file systems,
kernel schedulers. Your library index is exactly that kind of place: Put can be
called at any time.