A plain Binary Search Tree (BST) can degenerate into a linked list (insert 1,2,3,4,5 in order → height n n n → O ( n ) O(n) O ( n ) search). An AVL tree is a BST that fixes its own shape after every insert/delete so its height stays O ( log n ) O(\log n) O ( log n ) . The whole trick is: after a change, walk back up; the first node whose left/right heights differ by more than 1 gets a rotation that re-balances it. Master which rotation and you've mastered AVL.
A self-balancing Binary Search Tree in which, for every node, the balance factor satisfies ∣ B F ∣ ≤ 1 |BF| \le 1 ∣ B F ∣ ≤ 1 . Named after inventors Adelson-Velsky and Landis (1962).
Definition Balance factor (BF)
B F ( n o d e ) = h e i g h t ( n o d e . l e f t ) − h e i g h t ( n o d e . r i g h t ) BF(node) = height(node.left) - height(node.right) B F ( n o d e ) = h e i g h t ( n o d e . l e f t ) − h e i g h t ( n o d e . r i g h t )
By convention the height of an empty subtree is − 1 -1 − 1 and a single leaf has height 0 0 0 .
Allowed values: ==− 1 , 0 , + 1 -1, 0, +1 − 1 , 0 , + 1 ==. Anything outside means the node is unbalanced and needs a rotation.
B F = + 2 BF = +2 B F = + 2 → left-heavy (problem on the left)
B F = − 2 BF = -2 B F = − 2 → right-heavy (problem on the right)
Intuition Why balancing keeps height logarithmic
If the worst (sparsest) AVL tree of height h h h still contains many nodes, then any tree with n n n nodes can't be very tall. So we find the minimum number of nodes N ( h ) N(h) N ( h ) in a height-h h h AVL tree.
A rotation is a local re-pointering of 3 nodes that preserves the BST in-order ordering while reducing height. The shape of the imbalance tells you which one.
Let z z z = first unbalanced node going up, y y y = its taller child, x x x = y y y 's taller child.
Case
Shape
Fix
LL
z z z left-heavy, inserted in y y y 's left
one right rotation at z z z
RR
z z z right-heavy, inserted in y y y 's right
one left rotation at z z z
LR
z z z left-heavy, inserted in y y y 's right
left at y y y , then right at z z z
RL
z z z right-heavy, inserted in y y y 's left
right at y y y , then left at z z z
Definition AVL insert (recursive)
Do a normal BST insert (recurse, place leaf).
On the way back up , update_height(node).
Compute BF. If |BF|>1, identify case using BF and the key, rotate.
def insert (node, key):
if node is None : return Node(key)
if key < node.key: node.left = insert(node.left, key)
elif key > node.key: node.right = insert(node.right, key)
else : return node # no duplicates
update_height(node)
bf = balance(node)
# LL
if bf > 1 and key < node.left.key: return rotateRight(node)
# RR
if bf < - 1 and key > node.right.key: return rotateLeft(node)
# LR
if bf > 1 and key > node.left.key:
node.left = rotateLeft(node.left); return rotateRight(node)
# RL
if bf < - 1 and key < node.right.key:
node.right = rotateRight(node.right); return rotateLeft(node)
return node
Key fact: an insert needs at most ONE rotation (single or double) to restore balance everywhere.
Standard BST delete (leaf → remove; one child → splice; two children → replace with in-order successor, then delete that successor).
Walk back up, update heights.
Rebalance using BF — but here decide the case from the children's BF , not from a key:
bf = balance(node)
if bf > 1 :
if balance(node.left) >= 0 : return rotateRight(node) # LL
else : node.left = rotateLeft(node.left); return rotateRight(node) # LR
if bf < - 1 :
if balance(node.right) <= 0 : return rotateLeft(node) # RR
else : node.right = rotateRight(node.right); return rotateLeft(node) # RL
Difference from insert: a delete may trigger rotations at multiple levels (up to O ( log n ) O(\log n) O ( log n ) of them), because fixing one node can shorten the subtree and unbalance an ancestor.
Worked example Example 1 — LL case (insert 30, 20, 10)
Insert 30 → root.
Insert 20 → left of 30. BF(30)=0 − ( − 1 ) = 1 0-(-1)=1 0 − ( − 1 ) = 1 . OK.
Insert 10 → left of 20. Now BF(30)=1 − ( − 1 ) = 2 1-(-1)=2 1 − ( − 1 ) = 2 → unbalanced, left-heavy.
Why this step? 10 < 20 (left child's key), so the new node went into the left of the left → LL → single right rotation at 30.
Result: 20 as root, 10 left, 30 right. Balanced, height 1. ✅
Worked example Example 2 — LR case (insert 30, 10, 20)
30 root; 10 left of 30; 20 → right of 10.
BF(30)=1 − ( − 1 ) = 2 1-(-1)=2 1 − ( − 1 ) = 2 (left-heavy) but 20 > 10 → went right of left → LR .
Why this step? The zig-zag (left then right) needs straightening first.
Step A: rotateLeft(10) → subtree becomes 20 over 10. Now it's a clean LL.
Step B: rotateRight(30) → 20 root, 10 left, 30 right . ✅
Why two rotations? One rotation can't fix a bent path; the inner one makes it straight.
Worked example Example 3 — RL on delete
Tree: 50(root), 30 left, 70 right, 60 left-of-70. Delete 30.
BF(50)=h e i g h t ( L ) − h e i g h t ( R ) = ( − 1 ) − ( 1 ) = − 2 height(L)-height(R)=(-1)-(1)=-2 h e i g h t ( L ) − h e i g h t ( R ) = ( − 1 ) − ( 1 ) = − 2 → right-heavy.
Why this step? The right side is now taller after losing 30.
Check balance(70): its left (60) is taller → B F ( 70 ) = + 1 > 0 BF(70)=+1 >0 B F ( 70 ) = + 1 > 0 → RL case.
rotateRight(70) → 60 over 70; then rotateLeft(50) → 60 root, 50 left, 70 right . ✅
Common mistake Forgetting empty-subtree height =
− 1 -1 − 1
Why the wrong idea feels right: people set empty height to 0 0 0 "because there's nothing." Fix: with empty = − 1 =-1 = − 1 , a leaf gets height 0 0 0 and BF formulas come out clean (B F BF B F of a leaf = 0 =0 = 0 ). Using 0 0 0 shifts every BF by one and breaks detection.
Common mistake Updating heights top-down or only at the root
Why it feels right: "I changed the root, so update the root." Fix: after a rotation the lower node's height changed too . Always update_height(child) before update_height(parent), and update on the whole path back up .
Common mistake Choosing the rotation by counting nodes instead of by BF/key
Why it feels right: the tree looks lopsided. Fix: use the rule: sign of B F ( z ) BF(z) B F ( z ) tells left/right-heavy; key (insert) or child's BF (delete) tells straight vs bent → exactly one of LL/RR/LR/RL.
Common mistake Assuming delete needs at most one rotation
Why it feels right: insert only ever needs one. Fix: delete can cascade — keep rebalancing every ancestor up to the root.
Recall Feynman: explain to a 12-year-old
Imagine a tower of blocks where each block must have its left and right stacks almost the same height — never off by more than one. Every time you add or remove a block, you check from the spot upward: if one side got too tall, you tip the tower a little (a rotation) so it leans back to balanced. Because it never leans much, you can always find any block by going down only a few levels — fast! The "tip" comes in 4 flavors depending on which side got too tall and whether it's a straight lean or a zig-zag lean.
Mnemonic Remembering the four cases
"Same letters = single, mixed letters = double."
LL, RR (matching) → one rotation (rotate toward the short side).
LR, RL (mixed) → two rotations; first letter says "do that rotation on the child," second letter is the parent's fix.
Also: "rotate opposite to the heavy side." Left-heavy → rotate right .
What is the balance factor of a node? h e i g h t ( l e f t ) − h e i g h t ( r i g h t ) height(left) - height(right) h e i g h t ( l e f t ) − h e i g h t ( r i g h t ) , allowed values
− 1 , 0 , + 1 -1,0,+1 − 1 , 0 , + 1 .
What height is assigned to an empty subtree? − 1 -1 − 1 (so a leaf has height
0 0 0 ).
Which rotation fixes an LL imbalance? A single right rotation at the unbalanced node.
LR case fix? rotateLeft(child) then rotateRight(node).
RL case fix? rotateRight(child) then rotateLeft(node).
How do you tell LL from LR on insert? Both are left-heavy (
B F = + 2 BF=+2 B F = + 2 ); compare key with left child's key — smaller=LL, larger=LR.
Max rotations needed after one AVL insert? One (single or double).
Why can delete need many rotations? A rotation can shorten the subtree, unbalancing an ancestor, so you rebalance up to the root.
What recurrence gives the minimum nodes of a height-h h h AVL tree? N ( h ) = 1 + N ( h − 1 ) + N ( h − 2 ) N(h)=1+N(h-1)+N(h-2) N ( h ) = 1 + N ( h − 1 ) + N ( h − 2 ) — a shifted Fibonacci,
N ( h ) = F h + 3 − 1 N(h)=F_{h+3}-1 N ( h ) = F h + 3 − 1 .
Worst-case AVL height in terms of n n n ? ≈ 1.44 log 2 n = O ( log n ) \approx 1.44\log_2 n = O(\log n) ≈ 1.44 log 2 n = O ( log n ) .
On rotation, update which node's height first? The lower (child) node, then the parent.
Time complexity of search/insert/delete in AVL? O ( log n ) O(\log n) O ( log n ) each.
Binary Search Tree — AVL is a BST plus the balance invariant.
Tree Rotations — the shared primitive used by AVL and Red-Black Tree .
Red-Black Tree — looser balancing (height ≤ 2 log n \le 2\log n ≤ 2 log n ), fewer rotations on delete.
Fibonacci Numbers — bounds the minimum node count / height.
Big-O Notation — why O ( log n ) O(\log n) O ( log n ) height matters.
Heap vs AVL — both balanced, but heaps only order parent-child, not full in-order.
BF = +2 left-heavy or -2 right-heavy
Fibonacci recurrence gives
Balance Factor = hleft - hright
N of h = 1 + N h-1 + N h-2
Intuition Hinglish mein samjho
Dekho, normal BST ka problem ye hai ki agar tum sorted order me values insert karo (1,2,3,4,5), to tree ek seedhi line ban jaata hai — linked list jaisa — aur search O ( n ) O(n) O ( n ) ho jaata hai. AVL tree isi problem ko solve karta hai: ye har node pe balance factor maintain karta hai, jo hai h e i g h t ( l e f t ) − h e i g h t ( r i g h t ) height(left) - height(right) h e i g h t ( l e f t ) − h e i g h t ( r i g h t ) , aur ye sirf − 1 , 0 , + 1 -1, 0, +1 − 1 , 0 , + 1 ho sakta hai. Agar kisi node ka BF + 2 +2 + 2 ya − 2 -2 − 2 ho gaya, matlab tree imbalance ho gaya, to ek rotation karke usse seedha kar dete hain.
Char cases hote hain: LL (left side ke left me daala) → ek right rotation. RR (right ke right) → ek left rotation. LR (left ke right, zig-zag) → pehle child pe left, phir parent pe right. RL (right ke left) → pehle child pe right, phir parent pe left. Trick yaad rakho: same letters = single rotation, mixed letters = double rotation , aur hamesha heavy side ke opposite rotate karo.
Insert me ek important baat — ek insert ke baad maximum ek hi rotation lagti hai. Lekin delete me kayi levels pe rotation lag sakti hai, kyunki ek subtree chhota hone se uska ancestor imbalance ho sakta hai, isliye root tak rebalance karte raho. Rotation karte waqt hamesha neeche wale node ka height pehle update karo, phir upar wale ka.
Kyun important hai? Kyunki AVL ki height kabhi ≈ 1.44 log 2 n \approx 1.44\log_2 n ≈ 1.44 log 2 n se zyada nahi hoti (Fibonacci se prove hota hai), isliye search, insert, delete sab guaranteed O ( log n ) O(\log n) O ( log n ) . Interviews aur database indexing me ye concept bahut kaam aata hai.