← All Posts
DSA Series · Trees · Part 4

AVL Trees: Self-Balancing BSTs

The AVL Invariant

An AVL tree maintains the invariant: for every node, the heights of the left and right subtrees differ by at most 1. This guarantees O(log n) height.

Balance Factor

balance(node) = height(node.left) - height(node.right)
// Must be -1, 0, or +1 for a valid AVL tree
Balanced (AVL-valid) 10 bf=1 5 bf=1 15 bf=0 3 bf=0 Unbalanced (bf=2) 10 bf=2! 5 3
Balance factors, left tree is AVL-valid, right tree violates the invariant at root (bf=2).

Rotations

When an insertion or deletion causes a balance factor of +2 or -2, we fix it with rotations. There are four cases:

Right-Right → Left Rotation Before A B C After B A C Left-Left → Right Rotation Before C B A After B A C Left-Right and Right-Left cases require two rotations (double rotation).
Single rotations restore balance. Double rotations (LR, RL) combine both.

▶ Interactive Rotation Animation

Watch nodes smoothly move during each rotation type. Click a rotation to animate it.

▶ AVL Insertion with Auto-Rebalancing

Insert values into an AVL tree and watch it rebalance automatically with rotations.

C++ Implementation

TreeNode* rotateLeft(TreeNode* x) {
    TreeNode* y = x->right;
    x->right = y->left;
    y->left = x;
    x->height = 1 + std::max(height(x->left), height(x->right));
    y->height = 1 + std::max(height(y->left), height(y->right));
    return y;
}

TreeNode* rotateRight(TreeNode* y) {
    TreeNode* x = y->left;
    y->left = x->right;
    x->right = y;
    y->height = 1 + std::max(height(y->left), height(y->right));
    x->height = 1 + std::max(height(x->left), height(x->right));
    return x;
}

TreeNode* avlInsert(TreeNode* node, int val) {
    if (!node) return new TreeNode(val);
    if (val < node->val) node->left = avlInsert(node->left, val);
    else if (val > node->val) node->right = avlInsert(node->right, val);
    else return node;

    node->height = 1 + std::max(height(node->left), height(node->right));
    int bf = balance(node);

    if (bf > 1 && val < node->left->val) return rotateRight(node);
    if (bf < -1 && val > node->right->val) return rotateLeft(node);
    if (bf > 1 && val > node->left->val) {
        node->left = rotateLeft(node->left);
        return rotateRight(node);
    }
    if (bf < -1 && val < node->right->val) {
        node->right = rotateRight(node->right);
        return rotateLeft(node);
    }
    return node;
}

Summary