An AVL Tree (Adelson-Velsky and Landis) is a self-balancing Binary-Search Tree(s). It was the first such data structure to be invented.
In a standard BST, inserting sorted data (e.g., 1, 2, 3, 4) leads to a “skewed” tree that behaves like a Linked List(s) with search time. AVL trees solve this by automatically re-balancing themselves after every insertion or deletion to ensure the tree height remains logarithmic.
Vocab: Balance Factor
For every node in an AVL tree, the height difference between its left and right sub-trees (called the Balance Factor) must be at most 1.
- Allowed Values:
- Unbalanced: If the Balance Factor becomes or , the tree must be rebalanced via Rotations.
Time & Space Complexity Analysis
Because the tree is strictly balanced, the height is guaranteed to be . Time Complexity
| Operation | Time Complexity |
|---|---|
| Search | |
| Insert | |
| Delete |
Space Complexity:
AVL vs. Red/Black Trees
Both are self-balancing BSTs, but they have different performance characteristics:
- AVL Trees: More strictly balanced. This makes look-ups faster but insertion/deletion slower (due to more frequent rotations).
- Use Case: Read-heavy databases where data changes infrequently.
- Black Trees: Less strictly balanced. Faster insertion/deletion, slightly slower lookups.
- Use Case: General-purpose maps (e.g.,
std::mapin C++,BTreeMapin Rust, Linux Kernel schedulers).
Rotations
In an AVL Tree Re-balancing is triggered when a node’s Balance Factor reaches or . We perform rotations to strictly maintain logarithmic height.
1. Single Right Rotation (LL Case)
- Trigger: Root
yis Left heavy, and Left Childxis Left heavy. - Action: Promote
x.ymoves down to the right.x’s right subtree (T2) is adopted byy.
graph TD subgraph After [Balanced] x_new((x)) --> T1_new[T1] x_new --> y_new((y)) y_new --> T2_new[T2] y_new --> T3_new[T3] end subgraph Before [Left-Left Imbalance] y((y)) --> x((x)) y --> T3[T3] x --> T1[T1] x --> T2[T2] style y stroke:#f00,stroke-width:2px end
2. Single Left Rotation (RR Case)
- Trigger: Root
yis Right heavy, and Right Childxis Right heavy. - Action: Promote
x.ymoves down to the left.x’s left subtree (T2) is adopted byy.
graph TD subgraph After [Balanced] x_new((x)) --> y_new((y)) x_new --> T3_new[T3] y_new --> T1_new[T1] y_new --> T2_new[T2] end subgraph Before [Right-Right Imbalance] y((y)) --> T1[T1] y --> x((x)) x --> T2[T2] x --> T3[T3] style y stroke:#f00,stroke-width:2px end
3. Left-Right Rotation (LR Case)
- Trigger: Root
zis Left heavy, but Left Childyis Right heavy. - Action:
- Left Rotate
y: Converts the structure to the LL case. - Right Rotate
z: Fixes the resulting LL imbalance.
- Left Rotate
graph TD subgraph Step 2: Right Rotate z [Balanced] x2((x)) --> y2((y)) x2 --> z2((z)) y2 --> T1_f[T1] y2 --> T2_f[T2] z2 --> T3_f[T3] z2 --> T4_f[T4] end subgraph Step 1: Left Rotate y [Becomes LL Case] z1((z)) --> x1((x)) z1 --> T4_mid[T4] x1 --> y1((y)) x1 --> T3_mid[T3] y1 --> T1_mid[T1] y1 --> T2_mid[T2] end subgraph Before [Left-Right Imbalance] z((z)) --> y((y)) z --> T4[T4] y --> T1[T1] y --> x((x)) x --> T2[T2] x --> T3[T3] style z stroke:#f00,stroke-width:2px end
4. Right-Left Rotation (RL Case)
- Trigger: Root
zis Right heavy, but Right Childyis Left heavy. - Action:
- Right Rotate
y: Converts the structure to the RR case. - Left Rotate
z: Fixes the resulting RR imbalance.
- Right Rotate
graph TD subgraph Step 2: Left Rotate z [Balanced] x2((x)) --> z2((z)) x2 --> y2((y)) z2 --> T1_f[T1] z2 --> T2_f[T2] y2 --> T3_f[T3] y2 --> T4_f[T4] end subgraph Step 1: Right Rotate y [Becomes RR Case] z1((z)) --> T1_mid[T1] z1 --> x1((x)) x1 --> T2_mid[T2] x1 --> y1((y)) y1 --> T3_mid[T3] y1 --> T4_mid[T4] end subgraph Before [Right-Left Imbalance] z((z)) --> T1[T1] z --> y((y)) y --> x((x)) y --> T4[T4] x --> T2[T2] x --> T3[T3] style z stroke:#f00,stroke-width:2px end