Insert the key exactly as in a plain search tree: walk to where the search fails and attach a leaf. Then walk back up the path updating heights. If some node’s balance factor reaches +2 or −2, rebalance there and stop. The lowest such node is the one to fix, and there is at most one of them.
The two outside cases
Suppose node z has balance +2 — its left subtree is two taller — and the new key went into the LEFT subtree of z’s left child. That is the LL case, and one right rotation at z fixes it: the left child rises, z drops to its right, and the two sides come out equal. RR is the mirror image, fixed by one left rotation.
LL, keys 30 20 10 one right rotation at 30
30 (+2) 20 (0)
20 10 30
10
RR, keys 10 20 30 one left rotation at 10
10 (−2) 20 (0)
20 10 30
30
The two inside cases, and why one rotation is not enough
Now suppose z has balance +2 and the new key went into the RIGHT subtree of z’s left child — the LR case. A single right rotation at z lifts the left child, but the offending subtree was on that child’s right, so it lands back on the left of z and the tree is now −2 the other way. The fix is to rotate the child left first, converting LR into LL, and then rotate z right.
LR, keys 30 10 20
30 (+2) rotate 10 LEFT: 30 then 30 RIGHT:
10 20 20
20 10 10 30
the grandchild 20 ends up as the root, which is what a double rotation
always does: the INNER grandchild rises two levels
RL, keys 10 30 20 rotate 30 RIGHT, then 10 LEFT same result
The lab names the case at every rebalance and animates it. On the three-key sequences above it reports LL, LR and RL respectively, each with one rebalance, each ending at the same tree 20 with children 10 and 30 — the same final shape reached three different ways, which is worth seeing because it makes the case analysis feel less arbitrary.
Theorem · One rebalance per insertion sufficesAfter an AVL insertion, rebalancing the lowest unbalanced ancestor restores the invariant everywhere.
Before the insertion the subtree rooted at that node had some height h. The insertion made it h + 1, which is what unbalanced it. Both the single and the double rotation return the subtree to height h. So from that node upward nothing has changed height at all, and every ancestor’s balance factor is what it was before the insertion — which was legal. Hence one fix, at most two rotations, regardless of how tall the tree is.
The measurement, on the input that breaks a plain tree
Insert 1 through 10 in increasing order — the order that turns a plain search tree into a path. The lab runs both:
keys 1 2 3 4 5 6 7 8 9 10, in order
AVL plain BST
height 3 9
rebalances 6 —
comparisons 25
the six fixes, in order: RR at 3, RR at 5, RR at 6,
RR at 7, RR at 9, RR at 10
height bound from N(h) at n = 10: N(3) = 7 ≤ 10, N(4) = 12 > 10
so h ≤ 3, and the tree achieves it
Every one of the six fixes is the RR case, because every key arrives larger than everything present. Height 3 against 9, on the input that is worst for the plain tree and costs the AVL tree six rotations — one per rebalance, since RR is a single rotation. The bound from the N(h) table is 3, and the tree reaches it.
A mixed order shows all four cases and a smaller gap. On the thirteen keys 50 25 75 10 5 30 27 60 90 80 70 98 62 the lab reports four rebalances — LL at 5, LR at 30, RR at 80, RL at 62 — giving height 3 against the plain tree’s 4, with 33 comparisons. The gap is one level, because that order was already reasonably balanced. Which is the caution: the measured benefit of balancing depends entirely on the order you measured it on, and the guarantee — h ≤ 1.44 log₂ n for every order — is the reason to pay for it.