Launch your tech mastery with us—your coding journey starts now!
Course Content
Data Structure

AVL Trees

AVL Tree (named after inventors Adelson-Velsky and Landis) is a self-balancing Binary Search Tree where the difference between heights of left and right subtrees (Balance Factor) cannot be more than 1 for any node.

AVL Tree data structure illustration showing a self-balancing binary search tree with balance factors and height difference between left and right subtrees limited to 1.

Balance Factor

Balance Factor (BF) = Height(Left Subtree) – Height(Right Subtree)

For AVL tree: BF ∈ {-1, 0, 1}

AVL Tree Implementation

java
class AVLNode {
    int data, height;
    AVLNode left, right;
    
    AVLNode(int d) {
        data = d;
        height = 1;
    }
}

class AVLTree {
    AVLNode root;
    
    // Get height of node
    int height(AVLNode node) {
        if (node == null)
            return 0;
        return node.height;
    }
    
    // Get maximum of two integers
    int max(int a, int b) {
        return (a > b) ? a : b;
    }
    
    // Get balance factor of node
    int getBalance(AVLNode node) {
        if (node == null)
            return 0;
        return height(node.left) - height(node.right);
    }
    
    // Right rotate subtree rooted with y
    AVLNode rightRotate(AVLNode y) {
        AVLNode x = y.left;
        AVLNode T2 = x.right;
        
        // Perform rotation
        x.right = y;
        y.left = T2;
        
        // Update heights
        y.height = max(height(y.left), height(y.right)) + 1;
        x.height = max(height(x.left), height(x.right)) + 1;
        
        // Return new root
        return x;
    }
    
    // Left rotate subtree rooted with x
    AVLNode leftRotate(AVLNode x) {
        AVLNode y = x.right;
        AVLNode T2 = y.left;
        
        // Perform rotation
        y.left = x;
        x.right = T2;
        
        // Update heights
        x.height = max(height(x.left), height(x.right)) + 1;
        y.height = max(height(y.left), height(y.right)) + 1;
        
        // Return new root
        return y;
    }
    
    // Insert a key
    AVLNode insert(AVLNode node, int key) {
        // 1. Perform normal BST insertion
        if (node == null)
            return new AVLNode(key);
        
        if (key < node.data)
            node.left = insert(node.left, key);
        else if (key > node.data)
            node.right = insert(node.right, key);
        else // Duplicate keys not allowed
            return node;
        
        // 2. Update height of this ancestor node
        node.height = 1 + max(height(node.left), height(node.right));
        
        // 3. Get the balance factor
        int balance = getBalance(node);
        
        // 4. If node becomes unbalanced, then there are 4 cases
        
        // Left Left Case
        if (balance > 1 && key < node.left.data)
            return rightRotate(node);
        
        // Right Right Case
        if (balance < -1 && key > node.right.data)
            return leftRotate(node);
        
        // Left Right Case
        if (balance > 1 && key > node.left.data) {
            node.left = leftRotate(node.left);
            return rightRotate(node);
        }
        
        // Right Left Case
        if (balance < -1 && key < node.right.data) {
            node.right = rightRotate(node.right);
            return leftRotate(node);
        }
        
        // Return the unchanged node pointer
        return node;
    }
    
    // Find node with minimum value
    AVLNode minValueNode(AVLNode node) {
        AVLNode current = node;
        
        // Loop down to find the leftmost leaf
        while (current.left != null)
            current = current.left;
        
        return current;
    }
    
    // Delete a node
    AVLNode deleteNode(AVLNode root, int key) {
        // 1. Perform standard BST delete
        if (root == null)
            return root;
        
        if (key < root.data)
            root.left = deleteNode(root.left, key);
        else if (key > root.data)
            root.right = deleteNode(root.right, key);
        else {
            // Node with only one child or no child
            if ((root.left == null) || (root.right == null)) {
                AVLNode temp = null;
                if (temp == root.left)
                    temp = root.right;
                else
                    temp = root.left;
                
                // No child case
                if (temp == null) {
                    temp = root;
                    root = null;
                } else // One child case
                    root = temp;
            } else {
                // Node with two children
                AVLNode temp = minValueNode(root.right);
                root.data = temp.data;
                root.right = deleteNode(root.right, temp.data);
            }
        }
        
        // If tree had only one node
        if (root == null)
            return root;
        
        // 2. Update height of current node
        root.height = max(height(root.left), height(root.right)) + 1;
        
        // 3. Get balance factor
        int balance = getBalance(root);
        
        // 4. If unbalanced, fix it
        
        // Left Left Case
        if (balance > 1 && getBalance(root.left) >= 0)
            return rightRotate(root);
        
        // Left Right Case
        if (balance > 1 && getBalance(root.left) < 0) {
            root.left = leftRotate(root.left);
            return rightRotate(root);
        }
        
        // Right Right Case
        if (balance < -1 && getBalance(root.right) <= 0)
            return leftRotate(root);
        
        // Right Left Case
        if (balance < -1 && getBalance(root.right) > 0) {
            root.right = rightRotate(root.right);
            return leftRotate(root);
        }
        
        return root;
    }
    
    // Preorder traversal
    void preOrder(AVLNode node) {
        if (node != null) {
            System.out.print(node.data + " ");
            preOrder(node.left);
            preOrder(node.right);
        }
    }
    
    // Print tree structure
    void printTree(AVLNode node, String prefix, boolean isLeft) {
        if (node == null)
            return;
        
        System.out.println(prefix + (isLeft ? "├── " : "└── ") + node.data);
        
        if (node.left != null || node.right != null) {
            if (node.left != null)
                printTree(node.left, prefix + (isLeft ? "│   " : "    "), true);
            else
                System.out.println(prefix + (isLeft ? "│   " : "    ") + "├── null");
            
            if (node.right != null)
                printTree(node.right, prefix + (isLeft ? "│   " : "    "), false);
            else
                System.out.println(prefix + (isLeft ? "│   " : "    ") + "└── null");
        }
    }
    
    public static void main(String[] args) {
        AVLTree tree = new AVLTree();
        
        /* Constructing tree given in the above figure */
        tree.root = tree.insert(tree.root, 10);
        tree.root = tree.insert(tree.root, 20);
        tree.root = tree.insert(tree.root, 30);
        tree.root = tree.insert(tree.root, 40);
        tree.root = tree.insert(tree.root, 50);
        tree.root = tree.insert(tree.root, 25);
        
        System.out.println("Preorder traversal of AVL tree:");
        tree.preOrder(tree.root);
        
        System.out.println("\n\nTree structure:");
        tree.printTree(tree.root, "", false);
        
        System.out.println("\n\nDeleting 10...");
        tree.root = tree.deleteNode(tree.root, 10);
        
        System.out.println("Preorder traversal after deletion:");
        tree.preOrder(tree.root);
        
        System.out.println("\n\nTree structure after deletion:");
        tree.printTree(tree.root, "", false);
    }
}
```

**Output:**
```
Preorder traversal of AVL tree:
30 20 10 25 40 50 

Tree structure:
└── 30
    ├── 20
    │   ├── 10
    │   │   ├── null
    │   │   └── null
    │   └── 25
    │       ├── null
    │       └── null
    └── 40
        ├── null
        └── 50
            ├── null
            └── null

Deleting 10...
Preorder traversal after deletion:
30 20 25 40 50 

Tree structure after deletion:
└── 30
    ├── 20
    │   ├── null
    │   └── 25
    │       ├── null
    │       └── null
    └── 40
        ├── null
        └── 50
            ├── null
            └── null

AVL Rotation Examples

java
class AVLRotationExamples {
    
    public static void main(String[] args) {
        AVLTree tree = new AVLTree();
        
        System.out.println("=== Left-Left Case (Right Rotation) ===");
        System.out.println("Inserting: 30, 20, 10");
        tree.root = tree.insert(tree.root, 30);
        tree.root = tree.insert(tree.root, 20);
        tree.root = tree.insert(tree.root, 10);
        tree.printTree(tree.root, "", false);
        
        tree = new AVLTree();
        System.out.println("\n=== Right-Right Case (Left Rotation) ===");
        System.out.println("Inserting: 10, 20, 30");
        tree.root = tree.insert(tree.root, 10);
        tree.root = tree.insert(tree.root, 20);
        tree.root = tree.insert(tree.root, 30);
        tree.printTree(tree.root, "", false);
        
        tree = new AVLTree();
        System.out.println("\n=== Left-Right Case ===");
        System.out.println("Inserting: 30, 10, 20");
        tree.root = tree.insert(tree.root, 30);
        tree.root = tree.insert(tree.root, 10);
        tree.root = tree.insert(tree.root, 20);
        tree.printTree(tree.root, "", false);
        
        tree = new AVLTree();
        System.out.println("\n=== Right-Left Case ===");
        System.out.println("Inserting: 10, 30, 20");
        tree.root = tree.insert(tree.root, 10);
        tree.root = tree.insert(tree.root, 30);
        tree.root = tree.insert(tree.root, 20);
        tree.printTree(tree.root, "", false);
    }
}