Trees
AVL Trees
Self-balancing BSTs: balance factors, the four rotation cases (LL, RR, LR, RL), and an insertion that stays O(log n) whatever order the keys arrive in.
An AVL tree (named after Adelson-Velsky and Landis, 1962) is a BST that keeps itself balanced. After every insertion or deletion it checks each node's balance factor and fixes any imbalance with rotations.
Balance factor
balance factor = height(left subtree) − height(right subtree)
In an AVL tree, every node's balance factor must be −1, 0 or +1. If an insertion makes some node's balance factor +2 or −2, that node is rebalanced. This keeps the height at most about 1.44 log₂ n, so search, insert and delete are all O(log n) guaranteed.
The four imbalance cases
Let Z be the lowest unbalanced node on the path from the inserted key up to the root.
| Case | Inserted into | Fix |
|---|---|---|
| LL | left subtree of Z's left child | one right rotation at Z |
| RR | right subtree of Z's right child | one left rotation at Z |
| LR | right subtree of Z's left child | left rotation at the child, then right rotation at Z |
| RL | left subtree of Z's right child | right rotation at the child, then left rotation at Z |
LL case: right rotation
Inserting 30, 20, 10 makes 30 left-heavy (balance factor +2):
Rotate right at 30: the left child 20 moves up to become the root, 30 moves down to become 20's right child, and 20's old right subtree (empty here) becomes 30's new left subtree.
RR case: left rotation
Inserting 10, 20, 30 is the mirror image: rotate left at 10 and 20 becomes the root.
LR case: double rotation
Inserting 30, 10, 20: the imbalance is at 30 (left-heavy), but the new key went into the right of the left child. A single right rotation would not fix it. First rotate left at 10 (turning it into the LL case), then rotate right at 30. The result is again 20 with children 10 and 30.
Insertion in C
#include <stdio.h>
#include <stdlib.h>
typedef struct Node { int key, height; struct Node *left, *right; } Node;
int h(Node *n) { return n ? n->height : 0; }
int max(int a, int b) { return a > b ? a : b; }
void update(Node *n) { n->height = 1 + max(h(n->left), h(n->right)); }
int balance(Node *n) { return n ? h(n->left) - h(n->right) : 0; }
Node *rotateRight(Node *z) {
Node *y = z->left, *t = y->right;
y->right = z;
z->left = t;
update(z); update(y);
return y;
}
Node *rotateLeft(Node *z) {
Node *y = z->right, *t = y->left;
y->left = z;
z->right = t;
update(z); update(y);
return y;
}
Node *insert(Node *n, int key) {
if (!n) { n = malloc(sizeof(Node)); n->key = key; n->height = 1; n->left = n->right = NULL; return n; }
if (key < n->key) n->left = insert(n->left, key);
else if (key > n->key) n->right = insert(n->right, key);
else return n;
update(n);
int b = balance(n);
if (b > 1 && key < n->left->key) { printf(" LL at %d\n", n->key); return rotateRight(n); }
if (b < -1 && key > n->right->key) { printf(" RR at %d\n", n->key); return rotateLeft(n); }
if (b > 1 && key > n->left->key) { printf(" LR at %d\n", n->key); n->left = rotateLeft(n->left); return rotateRight(n); }
if (b < -1 && key < n->right->key) { printf(" RL at %d\n", n->key); n->right = rotateRight(n->right); return rotateLeft(n); }
return n;
}
void preorder(Node *r) { if (r) { printf("%d ", r->key); preorder(r->left); preorder(r->right); } }
int main(void) {
int keys[] = {10, 20, 30, 40, 50, 25};
Node *root = NULL;
for (int i = 0; i < 6; i++) {
printf("insert %d\n", keys[i]);
root = insert(root, keys[i]);
}
printf("Preorder: ");
preorder(root);
printf("\nHeight: %d (a plain BST built from the same keys has height 5)\n", h(root));
return 0;
}insert 10 insert 20 insert 30 RR at 10 insert 40 insert 50 RR at 30 insert 25 RL at 20 Preorder: 30 20 10 25 40 50 Height: 3 (a plain BST built from the same keys has height 5)
The final AVL tree for 10, 20, 30, 40, 50, 25:
Test yourself
4 questions · pick an answer to check it instantly
- 1
What balance factors are allowed in an AVL tree?
A node whose balance factor reaches ±2 must be rotated. - 2
Insert 10, 20, 30 into an empty AVL tree. Which rotation happens?
The tree becomes right-heavy along a straight line, so one left rotation at 10 fixes it. - 3
Inserting 30, 10, 20 creates which case?
The new key went into the right subtree of the left child of 30 — a double rotation is needed. - 4
Why are AVL operations O(log n) in the worst case?
Bounded height guarantees logarithmic search, insert and delete.