Deletion in an AVL Tree

Last Updated : 5 Feb, 2026

We have discussed Insertion of AVL Tree. In this post, we will follow a similar approach for deletion.

Steps to follow for deletion. 
To make sure that the given tree remains AVL after every deletion, we must augment the standard BST delete operation to perform some re-balancing. Following are two basic operations that can be performed to re-balance a BST without violating the BST property (keys(left) < key(root) < keys(right)). 

  1. Left Rotation
  2. Right Rotation
Deletion-in-an-AVL-Tree_
keys(T1) < key(x) < keys(T2) < key(y) < keys(T3)

Example:  

Try It Yourself
redirect icon
C++
#include <bits/stdc++.h>
using namespace std;

// An AVL tree node
class Node {
public:
    int key;
    Node *left;
    Node *right;
    int height;

    Node(int k) {
        key = k;
        left = nullptr;
        right = nullptr;
        height = 1;
    }
};

// A utility function to get the height 
// of the tree
int height(Node *N) {
    if (N == nullptr)
        return 0;
    return N->height;
}

// A utility function to right rotate 
// subtree rooted with y
Node *rightRotate(Node *y) {
    Node *x = y->left;
    Node *T2 = x->right;

    // Perform rotation
    x->right = y;
    y->left = T2;

    // Update heights
    y->height = 1 + max(height(y->left), height(y->right));
    // Fixed line below:
    x->height = 1 + max(height(x->left), height(x->right));

    // Return new root
    return x;
}

// A utility function to left rotate 
// subtree rooted with x
Node *leftRotate(Node *x) {
    Node *y = x->right;
    Node *T2 = y->left;

    // Perform rotation
    y->left = x;
    x->right = T2;

    // Update heights
    x->height = 1 + max(height(x->left),
                height(x->right));
    y->height = 1 + max(height(y->left),
                height(y->right));

    // Return new root
    return y;
}

// Get Balance factor of node N
int getBalance(Node *N) {
    if (N == nullptr)
        return 0;
    return height(N->left) - 
           height(N->right);
}

Node* insert(Node* node, int key) {
    // 1. Perform the normal BST rotation
    if (node == nullptr)
        return new Node(key);

    if (key < node->key)
        node->left = insert(node->left, key);
    else if (key > node->key)
        node->right = insert(node->right, key);
    else // Equal 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 of this 
    // ancestor node to check whether this 
    // node became unbalanced
    int balance = getBalance(node);

    // If this node becomes unbalanced, then 
    // there are 4 cases

    // Left Left Case
    if (balance > 1 && key < node->left->key)
        return rightRotate(node);

    // Right Right Case
    if (balance < -1 && key > node->right->key)
        return leftRotate(node);

    // Left Right Case
    if (balance > 1 && key > node->left->key) {
        node->left = leftRotate(node->left);
        return rightRotate(node);
    }

    // Right Left Case
    if (balance < -1 && key < node->right->key) {
        node->right = rightRotate(node->right);
        return leftRotate(node);
    }

    // return the (unchanged) node pointer
    return node;
}

// Given a non-empty binary search tree, 
// return the node with minimum key value 
// found in that tree. Note that the entire 
// tree does not need to be searched.
Node * minValueNode(Node* node) {
    Node* current = node;

    // loop down to find the leftmost leaf
    while (current->left != nullptr)
        current = current->left;

    return current;
}

// Recursive function to delete a node with 
// given key from subtree with given root. 
// It returns root of the modified subtree.
Node* deleteNode(Node* root, int key) {
    // STEP 1: PERFORM STANDARD BST DELETE
    if (root == nullptr)
        return root;

    // If the key to be deleted is smaller 
    // than the root's key, then it lies in 
    // left subtree
    if (key < root->key)
        root->left = deleteNode(root->left, key);

    // If the key to be deleted is greater 
    // than the root's key, then it lies in 
    // right subtree
    else if (key > root->key)
        root->right = deleteNode(root->right, key);

    // if key is same as root's key, then 
    // this is the node to be deleted
    else {
        // node with only one child or no child
        if ((root->left == nullptr) || 
            (root->right == nullptr)) {
            Node *temp = root->left ? 
                         root->left : root->right;

            // No child case
            if (temp == nullptr) {
                temp = root;
                root = nullptr;
            } else // One child case
                Node *temp = root->left ? root->left : root->right;
				delete root; // delete the current node
				return temp; // return the child to be linked to the parent
        } else {
            // node with two children: Get the 
            // inorder successor (smallest in 
            // the right subtree)
            Node* temp = minValueNode(root->right);

            // Copy the inorder successor's 
            // data to this node
            root->key = temp->key;

            // Delete the inorder successor
            root->right = deleteNode(root->right, temp->key);
        }
    }

    // If the tree had only one node then return
    if (root == nullptr)
        return root;

    // STEP 2: UPDATE HEIGHT OF THE CURRENT NODE
    root->height = 1 + max(height(root->left), 
                   height(root->right));

    // STEP 3: GET THE BALANCE FACTOR OF THIS 
    // NODE (to check whether this node 
    // became unbalanced)
    int balance = getBalance(root);

    // If this node becomes unbalanced, then 
    // there are 4 cases

    // 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;
}

// A utility function to print preorder 
// traversal of the tree. 
void preOrder(Node *root) {
    if (root != nullptr) {
        cout << root->key << " ";
        preOrder(root->left);
        preOrder(root->right);
    }
}

// Driver Code
int main() {
    Node *root = nullptr;

    // Constructing tree given in the 
    // above figure
    root = insert(root, 9);
    root = insert(root, 5);
    root = insert(root, 10);
    root = insert(root, 0);
    root = insert(root, 6);
    root = insert(root, 11);
    root = insert(root, -1);
    root = insert(root, 1);
    root = insert(root, 2);

    cout << "Preorder traversal of the "
            "constructed AVL tree is \n";
    preOrder(root);

    root = deleteNode(root, 10);

    cout << "\nPreorder traversal after"
            " deletion of 10 \n";
    preOrder(root);

    return 0;
}
Java
import java.util.ArrayList;
import java.util.List;

// An AVL tree node
class Node {
    public int key;
    public Node left;
    public Node right;
    public int height;

    public Node(int k) {
        key = k;
        left = null;
        right = null;
        height = 1;
    }
}

public class AVLTree {
    // A utility function to get the height of the tree
    private int height(Node N) {
        if (N == null)
            return 0;
        return N.height;
    }

    // A utility function to right rotate subtree rooted with y
    private Node rightRotate(Node y) {
        Node x = y.left;
        Node T2 = x.right;

        // Perform rotation
        x.right = y;
        y.left = T2;

        // Update heights
        y.height = 1 + Math.max(height(y.left), height(y.right));
        x.height = 1 + Math.max(height(x.left), height(x.right));

        // Return new root
        return x;
    }

    // A utility function to left rotate subtree rooted with x
    private Node leftRotate(Node x) {
        Node y = x.right;
        Node T2 = y.left;

        // Perform rotation
        y.left = x;
        x.right = T2;

        // Update heights
        x.height = 1 + Math.max(height(x.left), height(x.right));
        y.height = 1 + Math.max(height(y.left), height(y.right));

        // Return new root
        return y;
    }

    // Get Balance factor of node N
    private int getBalance(Node N) {
        if (N == null)
            return 0;
        return height(N.left) - height(N.right);
    }

    public Node insert(Node node, int key) {
        // 1. Perform the normal BST rotation
        if (node == null)
            return new Node(key);

        if (key < node.key)
            node.left = insert(node.left, key);
        else if (key > node.key)
            node.right = insert(node.right, key);
        else // Equal keys not allowed
            return node;

        // 2. Update height of this ancestor node
        node.height = 1 + Math.max(height(node.left), height(node.right));

        // 3. Get the balance factor of this ancestor node to check whether this node became unbalanced
        int balance = getBalance(node);

        // If this node becomes unbalanced, then there are 4 cases

        // Left Left Case
        if (balance > 1 && key < node.left.key)
            return rightRotate(node);

        // Right Right Case
        if (balance < -1 && key > node.right.key)
            return leftRotate(node);

        // Left Right Case
        if (balance > 1 && key > node.left.key) {
            node.left = leftRotate(node.left);
            return rightRotate(node);
        }

        // Right Left Case
        if (balance < -1 && key < node.right.key) {
            node.right = rightRotate(node.right);
            return leftRotate(node);
        }

        // return the (unchanged) node pointer
        return node;
    }

    // Given a non-empty binary search tree, return the node with minimum key value found in that tree. Note that the entire tree does not need to be searched.
    private Node minValueNode(Node node) {
        Node current = node;

        // loop down to find the leftmost leaf
        while (current.left!= null)
            current = current.left;

        return current;
    }

    // Recursive function to delete a node with given key from subtree with given root. It returns root of the modified subtree.
    public Node deleteNode(Node root, int key) {
        // STEP 1: PERFORM STANDARD BST DELETE
        if (root == null)
            return root;

        // If the key to be deleted is smaller than the root's key, then it lies in left subtree
        if (key < root.key)
            root.left = deleteNode(root.left, key);

        // If the key to be deleted is greater than the root's key, then it lies in right subtree
        else if (key > root.key)
            root.right = deleteNode(root.right, key);

        // if key is same as root's key, then this is the node to be deleted
        else {
            // node with only one child or no child
            if ((root.left == null) || (root.right == null)) {
                Node temp = root.left!= null? root.left : root.right;

                // No child case
                if (temp == null) {
                    temp = root;
                    root = null;
                } else // One child case
                    return temp;
            } else {
                // node with two children: Get the inorder successor (smallest in the right subtree)
                Node temp = minValueNode(root.right);

                // Copy the inorder successor's data to this node
                root.key = temp.key;

                // Delete the inorder successor
                root.right = deleteNode(root.right, temp.key);
            }
        }

        // If the tree had only one node then return
        if (root == null)
            return root;

        // STEP 2: UPDATE HEIGHT OF THE CURRENT NODE
        root.height = 1 + Math.max(height(root.left), height(root.right));

        // STEP 3: GET THE BALANCE FACTOR OF THIS NODE (to check whether this node became unbalanced)
        int balance = getBalance(root);

        // If this node becomes unbalanced, then there are 4 cases

        // 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;
    }

    // A utility function to print preorder traversal of the tree.
    private void preOrder(Node root) {
        if (root!= null) {
            System.out.print(root.key + " ");
            preOrder(root.left);
            preOrder(root.right);
        }
    }

    // Driver Code
    public static void main(String[] args) {
        AVLTree tree = new AVLTree();
        Node root = null;

        // Constructing tree given in the above figure
        root = tree.insert(root, 9);
        root = tree.insert(root, 5);
        root = tree.insert(root, 10);
        root = tree.insert(root, 0);
        root = tree.insert(root, 6);
        root = tree.insert(root, 11);
        root = tree.insert(root, -1);
        root = tree.insert(root, 1);
        root = tree.insert(root, 2);

        System.out.println("Preorder traversal of the constructed AVL tree is");
        tree.preOrder(root);

        root = tree.deleteNode(root, 10);

        System.out.println("\nPreorder traversal after deletion of 10");
        tree.preOrder(root);
    }
}
Python
import math

# An AVL tree node
class Node:
    def __init__(self, key):
        self.key = key
        self.left = None
        self.right = None
        self.height = 1

class AVLTree:
    # A utility function to get the height of the tree
    def height(self, N):
        if not N:
            return 0
        return N.height

    # A utility function to right rotate subtree rooted with y
    def rightRotate(self, y):
        x = y.left
        T2 = x.right

        # Perform rotation
        x.right = y
        y.left = T2

        # Update heights
        y.height = 1 + max(self.height(y.left), self.height(y.right))
        x.height = 1 + max(self.height(x.left), self.height(x.right))

        # Return new root
        return x

    # A utility function to left rotate subtree rooted with x
    def leftRotate(self, x):
        y = x.right
        T2 = y.left

        # Perform rotation
        y.left = x
        x.right = T2

        # Update heights
        x.height = 1 + max(self.height(x.left), self.height(x.right))
        y.height = 1 + max(self.height(y.left), self.height(y.right))

        # Return new root
        return y

    # Get Balance factor of node N
    def getBalance(self, N):
        if not N:
            return 0
        return self.height(N.left) - self.height(N.right)

    def insert(self, node, key):
        # 1. Perform the normal BST rotation
        if not node:
            return Node(key)

        if key < node.key:
            node.left = self.insert(node.left, key)
        elif key > node.key:
            node.right = self.insert(node.right, key)
        else: # Equal keys not allowed
            return node

        # 2. Update height of this ancestor node
        node.height = 1 + max(self.height(node.left), self.height(node.right))

        # 3. Get the balance factor of this ancestor node to check whether this node became unbalanced
        balance = self.getBalance(node)

        # If this node becomes unbalanced, then there are 4 cases
        # Left Left Case
        if balance > 1 and key < node.left.key:
            return self.rightRotate(node)

        # Right Right Case
        if balance < -1 and key > node.right.key:
            return self.leftRotate(node)

        # Left Right Case
        if balance > 1 and key > node.left.key:
            node.left = self.leftRotate(node.left)
            return self.rightRotate(node)

        # Right Left Case
        if balance < -1 and key < node.right.key:
            node.right = self.rightRotate(node.right)
            return self.leftRotate(node)

        # return the (unchanged) node pointer
        return node

    # Given a non-empty binary search tree, return the node with minimum key value found in that tree. Note that the entire tree does not need to be searched.
    def minValueNode(self, node):
        current = node

        # loop down to find the leftmost leaf
        while current.left is not None:
            current = current.left

        return current

    # Recursive function to delete a node with given key from subtree with given root. It returns root of the modified subtree.
    def deleteNode(self, root, key):
        # STEP 1: PERFORM STANDARD BST DELETE
        if not root:
            return root

        # If the key to be deleted is smaller than the root's key, then it lies in left subtree
        if key < root.key:
            root.left = self.deleteNode(root.left, key)
        # If the key to be deleted is greater than the root's key, then it lies in right subtree
        elif key > root.key:
            root.right = self.deleteNode(root.right, key)
        # if key is same as root's key, then this is the node to be deleted
        else:
            # node with only one child or no child
            if root.left is None or root.right is None:
                temp = root.left if root.left is not None else root.right
                if temp is None:
                    temp = root
                    root = None
                else: # One child case
                    root = temp
            else:
                # node with two children: Get the inorder successor (smallest in the right subtree)
                temp = self.minValueNode(root.right)
                # Copy the inorder successor's data to this node
                root.key = temp.key
                # Delete the inorder successor
                root.right = self.deleteNode(root.right, temp.key)

        if root is None:
            return root

        # STEP 2: UPDATE HEIGHT OF THE CURRENT NODE
        root.height = 1 + max(self.height(root.left), self.height(root.right))

        # STEP 3: GET THE BALANCE FACTOR OF THIS NODE (to check whether this node became unbalanced)
        balance = self.getBalance(root)

        # If this node becomes unbalanced, then there are 4 cases
        # Left Left Case
        if balance > 1 and self.getBalance(root.left) >= 0:
            return self.rightRotate(root)
        # Left Right Case
        if balance > 1 and self.getBalance(root.left) < 0:
            root.left = self.leftRotate(root.left)
            return self.rightRotate(root)
        # Right Right Case
        if balance < -1 and self.getBalance(root.right) <= 0:
            return self.leftRotate(root)
        # Right Left Case
        if balance < -1 and self.getBalance(root.right) > 0:
            root.right = self.rightRotate(root.right)
            return self.leftRotate(root)

        return root

    # A utility function to print preorder traversal of the tree.
    def preOrder(self, root):
        if root:
            print("{}".format(root.key), end=" ")
            self.preOrder(root.left)
            self.preOrder(root.right)

# Driver Code
if __name__ == '__main__':
    tree = AVLTree()
    root = None

    # Constructing tree given in the above figure
    root = tree.insert(root, 9)
    root = tree.insert(root, 5)
    root = tree.insert(root, 10)
    root = tree.insert(root, 0)
    root = tree.insert(root, 6)
    root = tree.insert(root, 11)
    root = tree.insert(root, -1)
    root = tree.insert(root, 1)
    root = tree.insert(root, 2)

    print("Preorder traversal of the constructed AVL tree is")
    tree.preOrder(root)

    root = tree.deleteNode(root, 10)

    print("\nPreorder traversal after deletion of 10")
    tree.preOrder(root)
C#
using System;

// An AVL tree node
public class Node
{
    public int key;
    public Node left, right;
    public int height;

    public Node(int item)
    {
        key = item;
        left = right = null;
        height = 1;
    }
}

public class AVLTree
{
    // A utility function to get the height of the tree
    public int height(Node N)
    {
        if (N == null)
            return 0;

        return N.height;
    }

    // A utility function to right rotate subtree rooted with y
    public Node rightRotate(Node y)
    {
        Node x = y.left;
        Node T2 = x.right;

        // Perform rotation
        x.right = y;
        y.left = T2;

        // Update heights
        y.height = Math.Max(height(y.left), height(y.right)) + 1;
        x.height = Math.Max(height(x.left), height(x.right)) + 1;

        // Return new root
        return x;
    }

    // A utility function to left rotate subtree rooted with x
    public Node leftRotate(Node x)
    {
        Node y = x.right;
        Node T2 = y.left;

        // Perform rotation
        y.left = x;
        x.right = T2;

        // Update heights
        x.height = Math.Max(height(x.left), height(x.right)) + 1;
        y.height = Math.Max(height(y.left), height(y.right)) + 1;

        // Return new root
        return y;
    }

    // Get Balance factor of node N
    public int getBalance(Node N)
    {
        if (N == null)
            return 0;

        return height(N.left) - height(N.right);
    }

    public Node insert(Node node, int key)
    {
        // 1. Perform the normal BST rotation
        if (node == null)
            return (new Node(key));

        if (key < node.key)
            node.left = insert(node.left, key);
        else if (key > node.key)
            node.right = insert(node.right, key);
        else // Equal keys not allowed
            return node;

        // 2. Update height of this ancestor node
        node.height = 1 + Math.Max(height(node.left), height(node.right));

        // 3. Get the balance factor of this ancestor node to check whether this node became unbalanced
        int balance = getBalance(node);

        // If this node becomes unbalanced, then there are 4 cases
        // Left Left Case
        if (balance > 1 && key < node.left.key)
            return rightRotate(node);

        // Right Right Case
        if (balance < -1 && key > node.right.key)
            return leftRotate(node);

        // Left Right Case
        if (balance > 1 && key > node.left.key)
        {
            node.left = leftRotate(node.left);
            return rightRotate(node);
        }

        // Right Left Case
        if (balance < -1 && key < node.right.key)
        {
            node.right = rightRotate(node.right);
            return leftRotate(node);
        }

        // return the (unchanged) node pointer
        return node;
    }

    // Given a non-empty binary search tree, return the node with minimum key value found in that tree. Note that the entire tree does not need to be searched.
    public Node minValueNode(Node node)
    {
        Node current = node;

        // loop down to find the leftmost leaf
        while (current.left!= null)
            current = current.left;

        return current;
    }

    // Recursive function to delete a node with given key from subtree with given root. It returns root of the modified subtree.
    public Node deleteNode(Node root, int key)
    {
        // STEP 1: PERFORM STANDARD BST DELETE
        if (root == null)
            return root;

        // If the key to be deleted is smaller than the root's key, then it lies in left subtree
        if (key < root.key)
            root.left = deleteNode(root.left, key);
        // If the key to be deleted is greater than the root's key, then it lies in right subtree
        else if (key > root.key)
            root.right = deleteNode(root.right, key);
        // if key is same as root's key, then this is the node to be deleted
        else
        {
            // node with only one child or no child
            if ((root.left == null) || (root.right == null))
            {
                Node temp = root.left!= null ? root.left : root.right;

                // No child case
                if (temp == null)
                {
                    temp = root;
                    root = null;
                }
                else // One child case
                    root = temp; // Copy the contents of the non-empty child
            }
            else
            {
                // node with two children: Get the inorder successor (smallest in the right subtree)
                Node temp = minValueNode(root.right);

                // Copy the inorder successor's data to this node
                root.key = temp.key;

                // Delete the inorder successor
                root.right = deleteNode(root.right, temp.key);
            }
        }

        if (root == null)
            return root;

        // STEP 2: UPDATE HEIGHT OF THE CURRENT NODE
        root.height = Math.Max(height(root.left), height(root.right)) + 1;

        // STEP 3: GET THE BALANCE FACTOR OF THIS NODE (to check whether this node became unbalanced)
        int balance = getBalance(root);

        // If this node becomes unbalanced, then there are 4 cases
        // 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;
    }

    // A utility function to print preorder traversal of the tree.
    public void preOrder(Node root)
    {
        if (root!= null)
        {
            Console.Write(root.key + " ");
            preOrder(root.left);
            preOrder(root.right);
        }
    }

    // Driver Code
    public static void Main(string[] args)
    {
        AVLTree tree = new AVLTree();
        Node root = null;

        // Constructing tree given in the above figure
        root = tree.insert(root, 9);
        root = tree.insert(root, 5);
        root = tree.insert(root, 10);
        root = tree.insert(root, 0);
        root = tree.insert(root, 6);
        root = tree.insert(root, 11);
        root = tree.insert(root, -1);
        root = tree.insert(root, 1);
        root = tree.insert(root, 2);

        Console.WriteLine("Preorder traversal of the constructed AVL tree is");
        tree.preOrder(root);

        root = tree.deleteNode(root, 10);

        Console.WriteLine("\nPreorder traversal after deletion of 10");
        tree.preOrder(root);
    }
}
JavaScript
'use strict';

// An AVL tree node
class Node {
    constructor(item) {
        this.key = item;
        this.left = null;
        this.right = null;
        this.height = 1;
    }
}

class AVLTree {
    // A utility function to get the height of the tree
    height(N) {
        if (N === null)
            return 0;

        return N.height;
    }

    // A utility function to right rotate subtree rooted with y
    rightRotate(y) {
        let x = y.left;
        let T2 = x.right;

        // Perform rotation
        x.right = y;
        y.left = T2;

        // Update heights
        y.height = Math.max(this.height(y.left), this.height(y.right)) + 1;
        x.height = Math.max(this.height(x.left), this.height(x.right)) + 1;

        // Return new root
        return x;
    }

    // A utility function to left rotate subtree rooted with x
    leftRotate(x) {
        let y = x.right;
        let T2 = y.left;

        // Perform rotation
        y.left = x;
        x.right = T2;

        // Update heights
        x.height = Math.max(this.height(x.left), this.height(x.right)) + 1;
        y.height = Math.max(this.height(y.left), this.height(y.right)) + 1;

        // Return new root
        return y;
    }

    // Get Balance factor of node N
    getBalance(N) {
        if (N === null)
            return 0;

        return this.height(N.left) - this.height(N.right);
    }

    insert(node, key) {
        // 1. Perform the normal BST rotation
        if (node === null)
            return new Node(key);

        if (key < node.key)
            node.left = this.insert(node.left, key);
        else if (key > node.key)
            node.right = this.insert(node.right, key);
        else // Equal keys not allowed
            return node;

        // 2. Update height of this ancestor node
        node.height = 1 + Math.max(this.height(node.left), this.height(node.right));

        // 3. Get the balance factor of this ancestor node to check whether this node became unbalanced
        let balance = this.getBalance(node);

        // If this node becomes unbalanced, then there are 4 cases
        // Left Left Case
        if (balance > 1 && key < node.left.key)
            return this.rightRotate(node);

        // Right Right Case
        if (balance < -1 && key > node.right.key)
            return this.leftRotate(node);

        // Left Right Case
        if (balance > 1 && key > node.left.key) {
            node.left = this.leftRotate(node.left);
            return this.rightRotate(node);
        }

        // Right Left Case
        if (balance < -1 && key < node.right.key) {
            node.right = this.rightRotate(node.right);
            return this.leftRotate(node);
        }

        // return the (unchanged) node pointer
        return node;
    }

    // Given a non-empty binary search tree, return the node with minimum key value found in that tree. Note that the entire tree does not need to be searched.
    minValueNode(node) {
        let current = node;

        // loop down to find the leftmost leaf
        while (current.left!== null)
            current = current.left;

        return current;
    }

    // Recursive function to delete a node with given key from subtree with given root. It returns root of the modified subtree.
    deleteNode(root, key) {
        // STEP 1: PERFORM STANDARD BST DELETE
        if (root === null)
            return root;

        // If the key to be deleted is smaller than the root's key, then it lies in left subtree
        if (key < root.key)
            root.left = this.deleteNode(root.left, key);
        // If the key to be deleted is greater than the root's key, then it lies in right subtree
        else if (key > root.key)
            root.right = this.deleteNode(root.right, key);
        // if key is same as root's key, then this is the node to be deleted
        else {
            // node with only one child or no child
            if ((root.left === null) || (root.right === null)) {
                let temp = root.left!== null? root.left : root.right;

                // No child case
                if (temp === null) {
                    temp = root;
                    root = null;
                } else // One child case
                    root = temp; // Copy the contents of the non-empty child
            } else {
                // node with two children: Get the inorder successor (smallest in the right subtree)
                let temp = this.minValueNode(root.right);

                // Copy the inorder successor's data to this node
                root.key = temp.key;

                // Delete the inorder successor
                root.right = this.deleteNode(root.right, temp.key);
            }
        }

        if (root === null)
            return root;

        // STEP 2: UPDATE HEIGHT OF THE CURRENT NODE
        root.height = Math.max(this.height(root.left), this.height(root.right)) + 1;

        // STEP 3: GET THE BALANCE FACTOR OF THIS NODE (to check whether this node became unbalanced)
        let balance = this.getBalance(root);

        // If this node becomes unbalanced, then there are 4 cases
        // Left Left Case
        if (balance > 1 && this.getBalance(root.left) >= 0)
            return this.rightRotate(root);

        // Left Right Case
        if (balance > 1 && this.getBalance(root.left) < 0) {
            root.left = this.leftRotate(root.left);
            return this.rightRotate(root);
        }

        // Right Right Case
        if (balance < -1 && this.getBalance(root.right) <= 0)
            return this.leftRotate(root);

        // Right Left Case
        if (balance < -1 && this.getBalance(root.right) > 0) {
            root.right = this.rightRotate(root.right);
            return this.leftRotate(root);
        }

        return root;
    }

    // A utility function to print preorder traversal of the tree.
    preOrder(root) {
        if (root!== null) {
            console.log(root.key + " ");
            this.preOrder(root.left);
            this.preOrder(root.right);
        }
    }
}

// Driver Code
let tree = new AVLTree();
let root = null;

// Constructing tree given in the above figure
root = tree.insert(root, 9);
root = tree.insert(root, 5);
root = tree.insert(root, 10);
root = tree.insert(root, 0);
root = tree.insert(root, 6);
root = tree.insert(root, 11);
root = tree.insert(root, -1);
root = tree.insert(root, 1);
root = tree.insert(root, 2);

console.log("Preorder traversal of the constructed AVL tree is");
tree.preOrder(root);

root = tree.deleteNode(root, 10);

console.log("\nPreorder traversal after deletion of 10");
tree.preOrder(root);

Output
Preorder traversal of the constructed AVL tree is 
9 1 0 -1 5 2 6 10 11 
Preorder traversal after deletion of 10 
1 0 -1 9 5 2 6 11 

Time Complexity: The rotation operations (left and right rotate) take constant time as only few pointers are being changed there. Updating the height and getting the balance factor also take constant time. So the time complexity of AVL delete remains same as BST delete which is O(h) where h is height of the tree. Since AVL tree is balanced, the height is O(log n). So time complexity of AVL delete is O(log n). 
Auxiliary Space: O(log n) for recursion call stack as we have written a recursive method to delete

Summary of Deletion in AVL Trees:

  • Deletion in AVL trees is similar to deletion in a Binary Search Tree (BST), but followed by rebalancing operations.
  • After deleting a node, the balance factor of ancestor nodes may change.
  • If the balance factor goes outside the range of -1 to +1, rotations (LL, RR, LR, RL) are required to restore balance.
  • The type of rotation depends on the balance factors of the affected node and its children.
  • Time complexity of deletion remains O(log n) due to the balanced nature of the tree.
Comment