Deletion in an AVL Tree (original) (raw)

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:

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: