Open In App

Insertion, Searching and Deletion in AVL trees containing a parent node pointer

Improve
Improve
Like Article
Like
Save
Share
Report

AVL tree is a self-balancing Binary Search Tree (BST) where the difference between heights of left and right subtrees cannot be more than one for all nodes. The insertion and deletion in AVL trees have been discussed in the previous article. In this article, insert, search, and delete operations are discussed on AVL trees that also have a parent pointer in their structure.

Definition of AVL tree node:

C++




struct AVLwithparent {
 
    // Pointer to the left and the
    // right subtree
    struct AVLwithparent* left;
    struct AVLwithparent* right;
 
    // Stores the data in the node
    int key;
 
    // Stores the parent pointer
    struct AVLwithparent* par;
 
    // Stores the height of the
    // current tree
    int height;
}


Java




class AVLwithParent {
    // Pointer to the left and the right subtree
    AVLwithParent left;
    AVLwithParent right;
 
    // Stores the data in the node
    int key;
 
    // Stores the parent pointer
    AVLwithParent par;
 
    // Stores the height of the current tree
    int height;
}


Python3




# Python code
 
class AVLwithParent:
    def __init__(self):
        # Pointer to the left and the right subtree
        self.left = None
        self.right = None
 
        # Stores the data in the node
        self.key = None
 
        # Stores the parent pointer
        self.par = None
 
        # Stores the height of the current tree
        self.height = None
 
# This code is contributed by princekumaras


C#




class AVLwithParent
{
    // Pointer to the left and the right subtree
    public AVLwithParent left;
    public AVLwithParent right;
 
    // Stores the data in the node
    public int key;
 
    // Stores the parent pointer
    public AVLwithParent par;
 
    // Stores the height of the current tree
    public int height;
}


Javascript




class AVLwithParent {
    constructor() {
        // Pointer to the left and the right subtree
        this.left = null;
        this.right = null;
 
        // Stores the data in the node
        this.key = null;
 
        // Stores the parent pointer
        this.par = null;
 
        // Stores the height of the current tree
        this.height = null;
    }
}


Representation of the Node:

Below is the example of an AVL tree containing a parent pointer:

Insert Operation: The insertion procedure is similar to that of a normal AVL tree without a parent pointer, but in this case, the parent pointers need to be updated with every insertion and rotation accordingly. Follow the steps below to perform insert operation:

  • Perform standard BST insert for the node to be placed at its correct position.
  • Increase the height of each node encountered by 1 while finding the correct position for the node to be inserted.
  • Update the parent and child pointers of the inserted node and its parent respectively.
  • Starting from the inserted node till the root node check if the AVL condition is satisfied for each node on this path.
  • If w is the node where the AVL condition is not satisfied then we have 4 cases:
    • Left Left Case: (If the left subtree of the left child of w has the inserted node)
    • Left Right Case: (If the right subtree of the left child of w has the inserted node)
    • Right Left Case: (If the left subtree of the right child of w has the inserted node)
    • Right Right Case: (If the right subtree of the right child of w has the inserted node)

Below is the implementation of the above approach:

C++




// C++ program for the above approach
#include <bits/stdc++.h>
using namespace std;
 
// AVL tree node
struct AVLwithparent {
    struct AVLwithparent* left;
    struct AVLwithparent* right;
    int key;
    struct AVLwithparent* par;
    int height;
};
 
// Function to update the height of
// a node according to its children's
// node's heights
void Updateheight(
    struct AVLwithparent* root)
{
    if (root != NULL) {
 
        // Store the height of the
        // current node
        int val = 1;
 
        // Store the height of the left
        // and right subtree
        if (root->left != NULL)
            val = root->left->height + 1;
 
        if (root->right != NULL)
            val = max(
                val, root->right->height + 1);
 
        // Update the height of the
        // current node
        root->height = val;
    }
}
 
// Function to handle Left Left Case
struct AVLwithparent* LLR(
    struct AVLwithparent* root)
{
    // Create a reference to the
    // left child
    struct AVLwithparent* tmpnode = root->left;
 
    // Update the left child of the
    // root to the right child of the
    // current left child of the root
    root->left = tmpnode->right;
 
    // Update parent pointer of the
    // left child of the root node
    if (tmpnode->right != NULL)
        tmpnode->right->par = root;
 
    // Update the right child of
    // tmpnode to root
    tmpnode->right = root;
 
    // Update parent pointer of
    // the tmpnode
    tmpnode->par = root->par;
 
    // Update the parent pointer
    // of the root
    root->par = tmpnode;
 
    // Update tmpnode as the left or the
    // right child of its parent pointer
    // according to its key value
    if (tmpnode->par != NULL
        && root->key < tmpnode->par->key) {
        tmpnode->par->left = tmpnode;
    }
    else {
        if (tmpnode->par != NULL)
            tmpnode->par->right = tmpnode;
    }
 
    // Make tmpnode as the new root
    root = tmpnode;
 
    // Update the heights
    Updateheight(root->left);
    Updateheight(root->right);
    Updateheight(root);
    Updateheight(root->par);
 
    // Return the root node
    return root;
}
 
// Function to handle Right Right Case
struct AVLwithparent* RRR(
    struct AVLwithparent* root)
{
    // Create a reference to the
    // right child
    struct AVLwithparent* tmpnode = root->right;
 
    // Update the right child of the
    // root as the left child of the
    // current right child of the root
    root->right = tmpnode->left;
 
    // Update parent pointer of the
    // right child of the root node
    if (tmpnode->left != NULL)
        tmpnode->left->par = root;
 
    // Update the left child of the
    // tmpnode to root
    tmpnode->left = root;
 
    // Update parent pointer of
    // the tmpnode
    tmpnode->par = root->par;
 
    // Update the parent pointer
    // of the root
    root->par = tmpnode;
 
    // Update tmpnode as the left or
    // the right child of its parent
    // pointer according to its key value
    if (tmpnode->par != NULL
        && root->key < tmpnode->par->key) {
        tmpnode->par->left = tmpnode;
    }
    else {
        if (tmpnode->par != NULL)
            tmpnode->par->right = tmpnode;
    }
 
    // Make tmpnode as the new root
    root = tmpnode;
 
    // Update the heights
    Updateheight(root->left);
    Updateheight(root->right);
    Updateheight(root);
    Updateheight(root->par);
 
    // Return the root node
    return root;
}
 
// Function to handle Left Right Case
struct AVLwithparent* LRR(
    struct AVLwithparent* root)
{
    root->left = RRR(root->left);
    return LLR(root);
}
 
// Function to handle right left case
struct AVLwithparent* RLR(
    struct AVLwithparent* root)
{
    root->right = LLR(root->right);
    return RRR(root);
}
 
// Function to insert a node in
// the AVL tree
struct AVLwithparent* Insert(
    struct AVLwithparent* root,
    struct AVLwithparent* parent,
    int key)
{
 
    if (root == NULL) {
 
        // Create and assign values
        // to a new node
        root = new struct AVLwithparent;
 
        // If the root is NULL
        if (root == NULL) {
            cout << "Error in memory"
                 << endl;
        }
 
        // Otherwise
        else {
            root->height = 1;
            root->left = NULL;
            root->right = NULL;
            root->par = parent;
            root->key = key;
        }
    }
 
    else if (root->key > key) {
 
        // Recur to the left subtree
        // to insert the node
        root->left = Insert(root->left,
                            root, key);
 
        // Store the heights of the
        // left and right subtree
        int firstheight = 0;
        int secondheight = 0;
 
        if (root->left != NULL)
            firstheight = root->left->height;
 
        if (root->right != NULL)
            secondheight = root->right->height;
 
        // Balance the tree if the
        // current node is not balanced
        if (abs(firstheight
                - secondheight)
            == 2) {
 
            if (root->left != NULL
                && key < root->left->key) {
 
                // Left Left Case
                root = LLR(root);
            }
            else {
 
                // Left Right Case
                root = LRR(root);
            }
        }
    }
 
    else if (root->key < key) {
 
        // Recur to the right subtree
        // to insert the node
        root->right = Insert(root->right,
                             root, key);
 
        // Store the heights of the
        // left and right subtree
        int firstheight = 0;
        int secondheight = 0;
 
        if (root->left != NULL)
            firstheight
                = root->left->height;
 
        if (root->right != NULL)
            secondheight = root->right->height;
 
        // Balance the tree if the
        // current node is not balanced
        if (abs(firstheight - secondheight) == 2) {
            if (root->right != NULL
                && key < root->right->key) {
 
                // Right Left Case
                root = RLR(root);
            }
            else {
 
                // Right Right Case
                root = RRR(root);
            }
        }
    }
 
    // Case when given key is already
    // in the tree
    else {
    }
 
    // Update the height of the
    // root node
    Updateheight(root);
 
    // Return the root node
    return root;
}
 
// Function to print the preorder
// traversal of the AVL tree
void printpreorder(
    struct AVLwithparent* root)
{
    // Print the node's value along
    // with its parent value
    cout << "Node: " << root->key
         << ", Parent Node: ";
 
    if (root->par != NULL)
        cout << root->par->key << endl;
    else
        cout << "NULL" << endl;
 
    // Recur to the left subtree
    if (root->left != NULL) {
        printpreorder(root->left);
    }
 
    // Recur to the right subtree
    if (root->right != NULL) {
        printpreorder(root->right);
    }
}
 
// Driver Code
int main()
{
    struct AVLwithparent* root;
    root = NULL;
 
    // Function Call to insert nodes
    root = Insert(root, NULL, 10);
    root = Insert(root, NULL, 20);
    root = Insert(root, NULL, 30);
    root = Insert(root, NULL, 40);
    root = Insert(root, NULL, 50);
    root = Insert(root, NULL, 25);
 
    // Function call to print the tree
    printpreorder(root);
}


Java




class AVLwithparent {
    int key;
    AVLwithparent left;
    AVLwithparent right;
    AVLwithparent par;
    int height;
 
    public AVLwithparent(int key) {
        this.key = key;
        this.left = null;
        this.right = null;
        this.par = null;
        this.height = 1;
    }
}
 
public class AVLTreeWithParent {
 
    // Function to update the height of a node based on its children's heights
    public static void updateHeight(AVLwithparent root) {
        if (root != null) {
            int leftHeight = (root.left != null) ? root.left.height : 0;
            int rightHeight = (root.right != null) ? root.right.height : 0;
            root.height = Math.max(leftHeight, rightHeight) + 1;
        }
    }
 
    // Left-Left Rotation (LLR) to balance the AVL tree
    public static AVLwithparent LLR(AVLwithparent root) {
        AVLwithparent tmpnode = root.left;
        root.left = tmpnode.right;
        if (tmpnode.right != null) {
            tmpnode.right.par = root;
        }
        tmpnode.right = root;
        tmpnode.par = root.par;
        root.par = tmpnode;
        if (tmpnode.par != null) {
            if (root.key < tmpnode.par.key) {
                tmpnode.par.left = tmpnode;
            } else {
                tmpnode.par.right = tmpnode;
            }
        }
        updateHeight(root);
        updateHeight(tmpnode);
        return tmpnode;
    }
 
    // Right-Right Rotation (RRR) to balance the AVL tree
    public static AVLwithparent RRR(AVLwithparent root) {
        AVLwithparent tmpnode = root.right;
        root.right = tmpnode.left;
        if (tmpnode.left != null) {
            tmpnode.left.par = root;
        }
        tmpnode.left = root;
        tmpnode.par = root.par;
        root.par = tmpnode;
        if (tmpnode.par != null) {
            if (root.key < tmpnode.par.key) {
                tmpnode.par.left = tmpnode;
            } else {
                tmpnode.par.right = tmpnode;
            }
        }
        updateHeight(root);
        updateHeight(tmpnode);
        return tmpnode;
    }
 
    // Left-Right Rotation (LRR) to balance the AVL tree
    public static AVLwithparent LRR(AVLwithparent root) {
        root.left = RRR(root.left);
        return LLR(root);
    }
 
    // Right-Left Rotation (RLR) to balance the AVL tree
    public static AVLwithparent RLR(AVLwithparent root) {
        root.right = LLR(root.right);
        return RRR(root);
    }
 
    // Function to insert a key into the AVL tree and balance the tree if needed
    public static AVLwithparent insert(AVLwithparent root, AVLwithparent parent, int key) {
        if (root == null) {
            root = new AVLwithparent(key);
            root.par = parent;
        } else if (root.key > key) {
            root.left = insert(root.left, root, key);
            int leftHeight = (root.left != null) ? root.left.height : 0;
            int rightHeight = (root.right != null) ? root.right.height : 0;
            if (Math.abs(leftHeight - rightHeight) == 2) {
                if (key < root.left.key) {
                    root = LLR(root);
                } else {
                    root = LRR(root);
                }
            }
        } else if (root.key < key) {
            root.right = insert(root.right, root, key);
            int leftHeight = (root.left != null) ? root.left.height : 0;
            int rightHeight = (root.right != null) ? root.right.height : 0;
            if (Math.abs(leftHeight - rightHeight) == 2) {
                if (key < root.right.key) {
                    root = RLR(root);
                } else {
                    root = RRR(root);
                }
            }
        }
        updateHeight(root);
        return root;
    }
 
    // Function to print the nodes of the AVL tree in preorder
    public static void printPreorder(AVLwithparent root) {
        if (root != null) {
            String parentKey = (root.par != null) ? Integer.toString(root.par.key) : "NULL";
            System.out.println("Node: " + root.key + ", Parent Node: " + parentKey);
            printPreorder(root.left);
            printPreorder(root.right);
        }
    }
 
    public static void main(String[] args) {
        AVLwithparent root = null;
        root = insert(root, null, 10);
        root = insert(root, null, 20);
        root = insert(root, null, 30);
        root = insert(root, null, 40);
        root = insert(root, null, 50);
        root = insert(root, null, 25);
        printPreorder(root);
    }
}


Python3




class AVLwithparent:
    def __init__(self, key):
        # Initialize a node with key, left and right child, parent, and height.
        self.left = None
        self.right = None
        self.key = key
        self.par = None
        self.height = 1
 
# Function to update the height of a node based on its children's heights
def update_height(root):
    if root is not None:
        left_height = root.left.height if root.left else 0  # Get the height of the left child
        right_height = root.right.height if root.right else 0  # Get the height of the right child
        root.height = max(left_height, right_height) + 1  # Update the height of the current node
 
# Left-Left Rotation (LLR) to balance the AVL tree
def LLR(root):
    # Perform a left rotation and then a right rotation
    # to balance the tree when there's an imbalance in the left subtree
    tmpnode = root.left
    root.left = tmpnode.right
    if tmpnode.right:
        tmpnode.right.par = root
    tmpnode.right = root
    tmpnode.par = root.par
    root.par = tmpnode
    if tmpnode.par:
        if root.key < tmpnode.par.key:
            tmpnode.par.left = tmpnode
        else:
            tmpnode.par.right = tmpnode
    update_height(root)
    update_height(tmpnode)
    return tmpnode
 
# Right-Right Rotation (RRR) to balance the AVL tree
def RRR(root):
    # Perform a right rotation and then a left rotation
    # to balance the tree when there's an imbalance in the right subtree
    tmpnode = root.right
    root.right = tmpnode.left
    if tmpnode.left:
        tmpnode.left.par = root
    tmpnode.left = root
    tmpnode.par = root.par
    root.par = tmpnode
    if tmpnode.par:
        if root.key < tmpnode.par.key:
            tmpnode.par.left = tmpnode
        else:
            tmpnode.par.right = tmpnode
    update_height(root)
    update_height(tmpnode)
    return tmpnode
 
# Left-Right Rotation (LRR) to balance the AVL tree
def LRR(root):
    # Perform a right rotation on the left child and then a left rotation on the root
    root.left = RRR(root.left)
    return LLR(root)
 
# Right-Left Rotation (RLR) to balance the AVL tree
def RLR(root):
    # Perform a left rotation on the right child and then a right rotation on the root
    root.right = LLR(root.right)
    return RRR(root)
 
# Function to insert a key into the AVL tree and balance the tree if needed
def insert(root, parent, key):
    if root is None:
        root = AVLwithparent(key)  # Create a new node if the current node is None
        root.par = parent  # Set the parent of the new node
    elif root.key > key:
        # Insert the key into the left subtree and balance the tree if needed
        root.left = insert(root.left, root, key)
        left_height = root.left.height if root.left else 0
        right_height = root.right.height if root.right else 0
        if abs(left_height - right_height) == 2:
            if key < root.left.key:
                root = LLR(root)
            else:
                root = LRR(root)
    elif root.key < key:
        # Insert the key into the right subtree and balance the tree if needed
        root.right = insert(root.right, root, key)
        left_height = root.left.height if root.left else 0
        right_height = root.right.height if root.right else 0
        if abs(left_height - right_height) == 2:
            if key < root.right.key:
                root = RLR(root)
            else:
                root = RRR(root)
    update_height(root)  # Update the height of the current node after insertion
    return root  # Return the root of the updated subtree
 
# Function to print the nodes of the AVL tree in preorder
def print_preorder(root):
    if root:
        parent_key = root.par.key if root.par else "NULL"  # Get the key of the parent node or "NULL" if it's None
        print(f"Node: {root.key}, Parent Node: {parent_key}"# Print the node and its parent
        print_preorder(root.left)  # Print the left subtree in preorder
        print_preorder(root.right)  # Print the right subtree in preorder
 
# Main function to demonstrate AVL tree operations
if __name__ == "__main__":
    root = None  # Initialize the root of the AVL tree as None
    # Insert keys into the AVL tree
    root = insert(root, None, 10)
    root = insert(root, None, 20)
    root = insert(root, None, 30)
    root = insert(root, None, 40)
    root = insert(root, None, 50)
    root = insert(root, None, 25)
    # Print the AVL tree in preorder
    print_preorder(root)


C#




using System;
 
public class AVLwithparent
{
    public AVLwithparent left;
    public AVLwithparent right;
    public int key;
    public AVLwithparent par;
    public int height;
}
 
public class Program
{
    public static void UpdateHeight(AVLwithparent root)
    {
        if (root != null)
        {
            int val = 1;
 
            if (root.left != null)
                val = root.left.height + 1;
 
            if (root.right != null)
                val = Math.Max(val, root.right.height + 1);
 
            root.height = val;
        }
    }
 
    public static AVLwithparent LLR(AVLwithparent root)
    {
        AVLwithparent tmpNode = root.left;
 
        root.left = tmpNode.right;
 
        if (tmpNode.right != null)
            tmpNode.right.par = root;
 
        tmpNode.right = root;
 
        tmpNode.par = root.par;
 
        root.par = tmpNode;
 
        if (tmpNode.par != null && root.key < tmpNode.par.key)
        {
            tmpNode.par.left = tmpNode;
        }
        else
        {
            if (tmpNode.par != null)
                tmpNode.par.right = tmpNode;
        }
 
        root = tmpNode;
 
        UpdateHeight(root.left);
        UpdateHeight(root.right);
        UpdateHeight(root);
        UpdateHeight(root.par);
 
        return root;
    }
 
    public static AVLwithparent RRR(AVLwithparent root)
    {
        AVLwithparent tmpNode = root.right;
 
        root.right = tmpNode.left;
 
        if (tmpNode.left != null)
            tmpNode.left.par = root;
 
        tmpNode.left = root;
 
        tmpNode.par = root.par;
 
        root.par = tmpNode;
 
        if (tmpNode.par != null && root.key < tmpNode.par.key)
        {
            tmpNode.par.left = tmpNode;
        }
        else
        {
            if (tmpNode.par != null)
                tmpNode.par.right = tmpNode;
        }
 
        root = tmpNode;
 
        UpdateHeight(root.left);
        UpdateHeight(root.right);
        UpdateHeight(root);
        UpdateHeight(root.par);
 
        return root;
    }
 
    public static AVLwithparent LRR(AVLwithparent root)
    {
        root.left = RRR(root.left);
        return LLR(root);
    }
 
    public static AVLwithparent RLR(AVLwithparent root)
    {
        root.right = LLR(root.right);
        return RRR(root);
    }
 
    public static AVLwithparent Insert(AVLwithparent root, AVLwithparent parent, int key)
    {
        if (root == null)
        {
            root = new AVLwithparent
            {
                height = 1,
                left = null,
                right = null,
                par = parent,
                key = key
            };
        }
        else if (root.key > key)
        {
            root.left = Insert(root.left, root, key);
 
            int firstHeight = 0;
            int secondHeight = 0;
 
            if (root.left != null)
                firstHeight = root.left.height;
 
            if (root.right != null)
                secondHeight = root.right.height;
 
            if (Math.Abs(firstHeight - secondHeight) == 2)
            {
                if (root.left != null && key < root.left.key)
                {
                    root = LLR(root);
                }
                else
                {
                    root = LRR(root);
                }
            }
        }
        else if (root.key < key)
        {
            root.right = Insert(root.right, root, key);
 
            int firstHeight = 0;
            int secondHeight = 0;
 
            if (root.left != null)
                firstHeight = root.left.height;
 
            if (root.right != null)
                secondHeight = root.right.height;
 
            if (Math.Abs(firstHeight - secondHeight) == 2)
            {
                if (root.right != null && key < root.right.key)
                {
                    root = RLR(root);
                }
                else
                {
                    root = RRR(root);
                }
            }
        }
        else
        {
            // Case when given key is already in the tree
        }
 
        UpdateHeight(root);
 
        return root;
    }
 
    public static void PrintPreorder(AVLwithparent root)
    {
        Console.Write("Node: " + root.key + ", Parent Node: ");
        if (root.par != null)
            Console.WriteLine(root.par.key);
        else
            Console.WriteLine("NULL");
 
        if (root.left != null)
        {
            PrintPreorder(root.left);
        }
 
        if (root.right != null)
        {
            PrintPreorder(root.right);
        }
    }
 
    public static void Main()
    {
        AVLwithparent root = null;
 
        root = Insert(root, null, 10);
        root = Insert(root, null, 20);
        root = Insert(root, null, 30);
        root = Insert(root, null, 40);
        root = Insert(root, null, 50);
        root = Insert(root, null, 25);
 
        PrintPreorder(root);
    }
}


Javascript




class AVLwithparent {
    constructor(key) {
        this.key = key;
        this.left = null;
        this.right = null;
        this.par = null;
        this.height = 1;
    }
}
 
// Function to update the height of a node based on its children's heights
function updateHeight(root) {
    if (root !== null) {
        const leftHeight = (root.left !== null) ? root.left.height : 0;
        const rightHeight = (root.right !== null) ? root.right.height : 0;
        root.height = Math.max(leftHeight, rightHeight) + 1;
    }
}
 
// Left-Left Rotation (LLR) to balance the AVL tree
function LLR(root) {
    const tmpnode = root.left;
    root.left = tmpnode.right;
    if (tmpnode.right !== null) {
        tmpnode.right.par = root;
    }
    tmpnode.right = root;
    tmpnode.par = root.par;
    root.par = tmpnode;
    if (tmpnode.par !== null) {
        if (root.key < tmpnode.par.key) {
            tmpnode.par.left = tmpnode;
        } else {
            tmpnode.par.right = tmpnode;
        }
    }
    updateHeight(root);
    updateHeight(tmpnode);
    return tmpnode;
}
 
// Right-Right Rotation (RRR) to balance the AVL tree
function RRR(root) {
    const tmpnode = root.right;
    root.right = tmpnode.left;
    if (tmpnode.left !== null) {
        tmpnode.left.par = root;
    }
    tmpnode.left = root;
    tmpnode.par = root.par;
    root.par = tmpnode;
    if (tmpnode.par !== null) {
        if (root.key < tmpnode.par.key) {
            tmpnode.par.left = tmpnode;
        } else {
            tmpnode.par.right = tmpnode;
        }
    }
    updateHeight(root);
    updateHeight(tmpnode);
    return tmpnode;
}
 
// Left-Right Rotation (LRR) to balance the AVL tree
function LRR(root) {
    root.left = RRR(root.left);
    return LLR(root);
}
 
// Right-Left Rotation (RLR) to balance the AVL tree
function RLR(root) {
    root.right = LLR(root.right);
    return RRR(root);
}
 
// Function to insert a key into the AVL tree and balance the tree if needed
function insert(root, parent, key) {
    if (root === null) {
        root = new AVLwithparent(key);
        root.par = parent;
    } else if (root.key > key) {
        root.left = insert(root.left, root, key);
        const leftHeight = (root.left !== null) ? root.left.height : 0;
        const rightHeight = (root.right !== null) ? root.right.height : 0;
        if (Math.abs(leftHeight - rightHeight) === 2) {
            if (key < root.left.key) {
                root = LLR(root);
            } else {
                root = LRR(root);
            }
        }
    } else if (root.key < key) {
        root.right = insert(root.right, root, key);
        const leftHeight = (root.left !== null) ? root.left.height : 0;
        const rightHeight = (root.right !== null) ? root.right.height : 0;
        if (Math.abs(leftHeight - rightHeight) === 2) {
            if (key < root.right.key) {
                root = RLR(root);
            } else {
                root = RRR(root);
            }
        }
    }
    updateHeight(root);
    return root;
}
 
// Function to print the nodes of the AVL tree in preorder
function printPreorder(root) {
    if (root !== null) {
        const parentKey = (root.par !== null) ? root.par.key : "NULL";
        console.log(`Node: ${root.key}, Parent Node: ${parentKey}`);
        printPreorder(root.left);
        printPreorder(root.right);
    }
}
 
// Example usage
let root = null;
root = insert(root, null, 10);
root = insert(root, null, 20);
root = insert(root, null, 30);
root = insert(root, null, 40);
root = insert(root, null, 50);
root = insert(root, null, 25);
printPreorder(root);


Output

Node: 30, Parent Node: NULL
Node: 20, Parent Node: 30
Node: 10, Parent Node: 20
Node: 25, Parent Node: 20
Node: 40, Parent Node: 30
Node: 50, Parent Node: 40



Time Complexity: O(log N), where N is the number of nodes of the tree.
Auxiliary Space: O(1)

Search Operation: The search operation in an AVL tree with parent pointers is similar to the search operation in a normal Binary Search Tree. Follow the steps below to perform search operation:

  • Start from the root node.
  • If the root node is NULL, return false.
  • Check if the current node’s value is equal to the value of the node to be searched. If yes, return true.
  • If the current node’s value is less than searched key then recur to the right subtree.
  • If the current node’s value is greater than searched key then recur to the left subtree.

Below is the implementation of the above approach:

C++




// C++ program for the above approach
#include <bits/stdc++.h>
using namespace std;
 
// AVL tree node
struct AVLwithparent {
    struct AVLwithparent* left;
    struct AVLwithparent* right;
    int key;
    struct AVLwithparent* par;
    int height;
};
 
// Function to update the height of
// a node according to its children's
// node's heights
void Updateheight(struct AVLwithparent* root)
{
    if (root != NULL) {
 
        // Store the height of the
        // current node
        int val = 1;
 
        // Store the height of the left
        // and the right subtree
        if (root->left != NULL)
            val = root->left->height + 1;
 
        if (root->right != NULL)
            val = max(
                val, root->right->height + 1);
 
        // Update the height of the
        // current node
        root->height = val;
    }
}
 
// Function to handle Left Left Case
struct AVLwithparent* LLR(
    struct AVLwithparent* root)
{
    // Create a reference to the
    // left child
    struct AVLwithparent* tmpnode = root->left;
 
    // Update the left child of the
    // root to the right child of the
    // current left child of the root
    root->left = tmpnode->right;
 
    // Update parent pointer of the left
    // child of the root node
    if (tmpnode->right != NULL)
        tmpnode->right->par = root;
 
    // Update the right child of
    // tmpnode to root
    tmpnode->right = root;
 
    // Update parent pointer of tmpnode
    tmpnode->par = root->par;
 
    // Update the parent pointer of root
    root->par = tmpnode;
 
    // Update tmpnode as the left or
    // the right child of its parent
    // pointer according to its key value
    if (tmpnode->par != NULL
        && root->key < tmpnode->par->key) {
        tmpnode->par->left = tmpnode;
    }
    else {
        if (tmpnode->par != NULL)
            tmpnode->par->right = tmpnode;
    }
 
    // Make tmpnode as the new root
    root = tmpnode;
 
    // Update the heights
    Updateheight(root->left);
    Updateheight(root->right);
    Updateheight(root);
    Updateheight(root->par);
 
    // Return the root node
    return root;
}
 
// Function to handle Right Right Case
struct AVLwithparent* RRR(
    struct AVLwithparent* root)
{
    // Create a reference to the
    // right child
    struct AVLwithparent* tmpnode = root->right;
 
    // Update the right child of the
    // root as the left child of the
    // current right child of the root
    root->right = tmpnode->left;
 
    // Update parent pointer of the right
    // child of the root node
    if (tmpnode->left != NULL)
        tmpnode->left->par = root;
 
    // Update the left child of the
    // tmpnode to root
    tmpnode->left = root;
 
    // Update parent pointer of tmpnode
    tmpnode->par = root->par;
 
    // Update the parent pointer of root
    root->par = tmpnode;
 
    // Update tmpnode as the left or
    // the right child of its parent
    // pointer according to its key value
    if (tmpnode->par != NULL
        && root->key < tmpnode->par->key) {
        tmpnode->par->left = tmpnode;
    }
    else {
        if (tmpnode->par != NULL)
            tmpnode->par->right = tmpnode;
    }
 
    // Make tmpnode as the new root
    root = tmpnode;
 
    // Update the heights
    Updateheight(root->left);
    Updateheight(root->right);
    Updateheight(root);
    Updateheight(root->par);
 
    // Return the root node
    return root;
}
 
// Function to handle Left Right Case
struct AVLwithparent* LRR(
    struct AVLwithparent* root)
{
    root->left = RRR(root->left);
    return LLR(root);
}
 
// Function to handle right left case
struct AVLwithparent* RLR(
    struct AVLwithparent* root)
{
    root->right = LLR(root->right);
    return RRR(root);
}
 
// Function to insert a node in
// the AVL tree
struct AVLwithparent* Insert(
    struct AVLwithparent* root,
    struct AVLwithparent* parent,
    int key)
{
 
    if (root == NULL) {
 
        // Create and assign values
        // to a new node
        root = new struct AVLwithparent;
        if (root == NULL) {
            cout << "Error in memory" << endl;
        }
 
        // Otherwise
        else {
            root->height = 1;
            root->left = NULL;
            root->right = NULL;
            root->par = parent;
            root->key = key;
        }
    }
 
    else if (root->key > key) {
 
        // Recur to the left subtree
        // to insert the node
        root->left = Insert(root->left,
                            root, key);
 
        // Stores the heights of the
        // left and right subtree
        int firstheight = 0;
        int secondheight = 0;
 
        if (root->left != NULL)
            firstheight = root->left->height;
 
        if (root->right != NULL)
            secondheight = root->right->height;
 
        // Balance the tree if the
        // current node is not balanced
        if (abs(firstheight
                - secondheight)
            == 2) {
 
            if (root->left != NULL
                && key < root->left->key) {
 
                // Left Left Case
                root = LLR(root);
            }
            else {
 
                // Left Right Case
                root = LRR(root);
            }
        }
    }
 
    else if (root->key < key) {
 
        // Recur to the right subtree
        // to insert the node
        root->right = Insert(root->right, root, key);
 
        // Store the heights of the left
        // and right subtree
        int firstheight = 0;
        int secondheight = 0;
 
        if (root->left != NULL)
            firstheight = root->left->height;
 
        if (root->right != NULL)
            secondheight = root->right->height;
 
        // Balance the tree if the
        // current node is not balanced
        if (abs(firstheight
                - secondheight)
            == 2) {
            if (root->right != NULL
                && key < root->right->key) {
 
                // Right Left Case
                root = RLR(root);
            }
            else {
 
                // Right Right Case
                root = RRR(root);
            }
        }
    }
 
    // Case when given key is
    // already in tree
    else {
    }
 
    // Update the height of the
    // root node
    Updateheight(root);
 
    // Return the root node
    return root;
}
 
// Function to find a key in AVL tree
bool AVLsearch(
    struct AVLwithparent* root, int key)
{
    // If root is NULL
    if (root == NULL)
        return false;
 
    // If found, return true
    else if (root->key == key)
        return true;
 
    // Recur to the left subtree if
    // the current node's value is
    // greater than key
    else if (root->key > key) {
        bool val = AVLsearch(root->left, key);
        return val;
    }
 
    // Otherwise, recur to the
    // right subtree
    else {
        bool val = AVLsearch(root->right, key);
        return val;
    }
}
 
// Driver Code
int main()
{
    struct AVLwithparent* root;
    root = NULL;
 
    // Function call to insert the nodes
    root = Insert(root, NULL, 10);
    root = Insert(root, NULL, 20);
    root = Insert(root, NULL, 30);
    root = Insert(root, NULL, 40);
    root = Insert(root, NULL, 50);
    root = Insert(root, NULL, 25);
 
    // Function call to search for a node
    bool found = AVLsearch(root, 40);
    if (found)
        cout << "value found";
    else
        cout << "value not found";
 
    return 0;
}


Java




class AVLwithparent {
    AVLwithparent left, right, par;
    int key;
    int height;
 
    // Constructor
    public AVLwithparent(int key, AVLwithparent parent) {
        this.key = key;
        this.par = parent;
        this.height = 1;
    }
}
 
public class AVLTree {
    // Function to update the height of a node according to its children's node's heights
    public static void updateHeight(AVLwithparent root) {
        if (root != null) {
            int val = 1;
 
            if (root.left != null)
                val = root.left.height + 1;
 
            if (root.right != null)
                val = Math.max(val, root.right.height + 1);
 
            root.height = val;
        }
    }
 
    // Function to handle Left Left Case
    public static AVLwithparent llr(AVLwithparent root) {
        AVLwithparent tmpnode = root.left;
 
        root.left = tmpnode.right;
 
        if (tmpnode.right != null)
            tmpnode.right.par = root;
 
        tmpnode.right = root;
 
        tmpnode.par = root.par;
 
        if (tmpnode.par != null && root.key < tmpnode.par.key)
            tmpnode.par.left = tmpnode;
        else {
            if (tmpnode.par != null)
                tmpnode.par.right = tmpnode;
        }
 
        root = tmpnode;
 
        updateHeight(root.left);
        updateHeight(root.right);
        updateHeight(root);
        updateHeight(root.par);
 
        return root;
    }
 
    // Function to handle Right Right Case
    public static AVLwithparent rrr(AVLwithparent root) {
        AVLwithparent tmpnode = root.right;
 
        root.right = tmpnode.left;
 
        if (tmpnode.left != null)
            tmpnode.left.par = root;
 
        tmpnode.left = root;
 
        tmpnode.par = root.par;
 
        if (tmpnode.par != null && root.key < tmpnode.par.key)
            tmpnode.par.left = tmpnode;
        else {
            if (tmpnode.par != null)
                tmpnode.par.right = tmpnode;
        }
 
        root = tmpnode;
 
        updateHeight(root.left);
        updateHeight(root.right);
        updateHeight(root);
        updateHeight(root.par);
 
        return root;
    }
 
    // Function to handle Left Right Case
    public static AVLwithparent lrr(AVLwithparent root) {
        root.left = rrr(root.left);
        return llr(root);
    }
 
    // Function to handle right left case
    public static AVLwithparent rlr(AVLwithparent root) {
        root.right = llr(root.right);
        return rrr(root);
    }
 
    // Function to insert a node in the AVL tree
    public static AVLwithparent insert(AVLwithparent root, AVLwithparent parent, int key) {
        if (root == null) {
            root = new AVLwithparent(key, parent);
        } else if (root.key > key) {
            root.left = insert(root.left, root, key);
 
            int firstHeight = (root.left != null) ? root.left.height : 0;
            int secondHeight = (root.right != null) ? root.right.height : 0;
 
            if (Math.abs(firstHeight - secondHeight) == 2) {
                if (root.left != null && key < root.left.key)
                    root = llr(root);
                else
                    root = lrr(root);
            }
        } else if (root.key < key) {
            root.right = insert(root.right, root, key);
 
            int firstHeight = (root.left != null) ? root.left.height : 0;
            int secondHeight = (root.right != null) ? root.right.height : 0;
 
            if (Math.abs(firstHeight - secondHeight) == 2) {
                if (root.right != null && key < root.right.key)
                    root = rlr(root);
                else
                    root = rrr(root);
            }
        }
 
        updateHeight(root);
        return root;
    }
 
    // Function to find a key in AVL tree
    public static boolean avlSearch(AVLwithparent root, int key) {
        if (root == null)
            return false;
        else if (root.key == key)
            return true;
        else if (root.key > key)
            return avlSearch(root.left, key);
        else
            return avlSearch(root.right, key);
    }
 
    // Driver Code
    public static void main(String[] args) {
        AVLwithparent root = null;
 
        root = insert(root, null, 10);
        root = insert(root, null, 20);
        root = insert(root, null, 30);
        root = insert(root, null, 40);
        root = insert(root, null, 50);
        root = insert(root, null, 25);
 
        boolean found = avlSearch(root, 40);
 
        if (found)
            System.out.println("Value found");
        else
            System.out.println("Value not found");
    }
}


Python3




# Python program for the above approach
 
# AVL tree node
class AVLwithparent:
    def __init__(self, key, parent=None):
        self.left = None
        self.right = None
        self.key = key
        self.par = parent
        self.height = 1
 
# Function to update the height of
# a node according to its children's
# node's heights
def update_height(root):
    if root is not None:
 
        # Store the height of the
        # current node
        val = 1
 
        # Store the height of the left
        # and the right subtree
        if root.left is not None:
            val = root.left.height + 1
 
        if root.right is not None:
            val = max(val, root.right.height + 1)
 
        # Update the height of the
        # current node
        root.height = val
 
# Function to handle Left Left Case
def llr(root):
    # Create a reference to the
    # left child
    tmp_node = root.left
 
    # Update the left child of the
    # root to the right child of the
    # current left child of the root
    root.left = tmp_node.right
 
    # Update parent pointer of the left
    # child of the root node
    if tmp_node.right is not None:
        tmp_node.right.par = root
 
    # Update the right child of
    # tmp_node to root
    tmp_node.right = root
 
    # Update parent pointer of tmp_node
    tmp_node.par = root.par
 
    # Update the parent pointer of root
    root.par = tmp_node
 
    # Update tmp_node as the left or
    # the right child of its parent
    # pointer according to its key value
    if tmp_node.par is not None and root.key < tmp_node.par.key:
        tmp_node.par.left = tmp_node
    else:
        if tmp_node.par is not None:
            tmp_node.par.right = tmp_node
 
    # Make tmp_node as the new root
    root = tmp_node
 
    # Update the heights
    update_height(root.left)
    update_height(root.right)
    update_height(root)
    update_height(root.par)
 
    # Return the root node
    return root
 
# Function to handle Right Right Case
def rrr(root):
    # Create a reference to the
    # right child
    tmp_node = root.right
 
    # Update the right child of the
    # root as the left child of the
    # current right child of the root
    root.right = tmp_node.left
 
    # Update parent pointer of the right
    # child of the root node
    if tmp_node.left is not None:
        tmp_node.left.par = root
 
    # Update the left child of the
    # tmp_node to root
    tmp_node.left = root
 
    # Update parent pointer of tmp_node
    tmp_node.par = root.par
 
    # Update the parent pointer of root
    root.par = tmp_node
 
    # Update tmp_node as the left or
    # the right child of its parent
    # pointer according to its key value
    if tmp_node.par is not None and root.key < tmp_node.par.key:
        tmp_node.par.left = tmp_node
    else:
        if tmp_node.par is not None:
            tmp_node.par.right = tmp_node
 
    # Make tmp_node as the new root
    root = tmp_node
 
    # Update the heights
    update_height(root.left)
    update_height(root.right)
    update_height(root)
    update_height(root.par)
 
    # Return the root node
    return root
 
# Function to handle Left Right Case
def lrr(root):
    root.left = rrr(root.left)
    return llr(root)
 
# Function to handle Right Left Case
def rlr(root):
    root.right = llr(root.right)
    return rrr(root)
 
# Function to insert a node in
# the AVL tree
def insert(root, parent, key):
    if root is None:
 
        # Create and assign values
        # to a new node
        root = AVLwithparent(key, parent)
 
    else:
        if root.key > key:
 
            # Recur to the left subtree
            # to insert the node
            root.left = insert(root.left, root, key)
 
            # Stores the heights of the
            # left and right subtree
            first_height = 0
            second_height = 0
 
            if root.left is not None:
                first_height = root.left.height
 
            if root.right is not None:
                second_height = root.right.height
 
            # Balance the tree if the
            # current node is not balanced
            if abs(first_height - second_height) == 2:
 
                if root.left is not None and key < root.left.key:
 
                    # Left Left Case
                    root = llr(root)
                else:
 
                    # Left Right Case
                    root = lrr(root)
 
        elif root.key < key:
 
            # Recur to the right subtree
            # to insert the node
            root.right = insert(root.right, root, key)
 
            # Store the heights of the left
            # and right subtree
            first_height = 0
            second_height = 0
 
            if root.left is not None:
                first_height = root.left.height
 
            if root.right is not None:
                second_height = root.right.height
 
            # Balance the tree if the
            # current node is not balanced
            if abs(first_height - second_height) == 2:
                if root.right is not None and key < root.right.key:
 
                    # Right Left Case
                    root = rlr(root)
                else:
 
                    # Right Right Case
                    root = rrr(root)
 
    # Update the height of the
    # root node
    update_height(root)
 
    # Return the root node
    return root
 
# Function to find a key in AVL tree
def avl_search(root, key):
    # If root is None
    if root is None:
        return False
 
    # If found, return True
    elif root.key == key:
        return True
 
    # Recur to the left subtree if
    # the current node's value is
    # greater than key
    elif root.key > key:
        return avl_search(root.left, key)
 
    # Otherwise, recur to the
    # right subtree
    else:
        return avl_search(root.right, key)
 
# Driver Code
if __name__ == "__main__":
    root = None
 
    # Function call to insert the nodes
    root = insert(root, None, 10)
    root = insert(root, None, 20)
    root = insert(root, None, 30)
    root = insert(root, None, 40)
    root = insert(root, None, 50)
    root = insert(root, None, 25)
 
    # Function call to search for a node
    found = avl_search(root, 40)
    if found:
        print("Value found")
    else:
        print("Value not found")


C#




using System;
 
// AVL tree node
public class AVLwithparent
{
    public AVLwithparent left;
    public AVLwithparent right;
    public int key;
    public AVLwithparent par;
    public int height;
}
 
public class AVLTree
{
    // Function to update the height of a node according to its children's node's heights
    public static void UpdateHeight(AVLwithparent root)
    {
        if (root != null)
        {
            int val = 1;
 
            if (root.left != null)
                val = root.left.height + 1;
 
            if (root.right != null)
                val = Math.Max(val, root.right.height + 1);
 
            root.height = val;
        }
    }
 
    // Function to handle Left Left Case
    public static AVLwithparent LLR(AVLwithparent root)
    {
        AVLwithparent tmpnode = root.left;
 
        root.left = tmpnode.right;
 
        if (tmpnode.right != null)
            tmpnode.right.par = root;
 
        tmpnode.right = root;
 
        tmpnode.par = root.par;
 
        if (tmpnode.par != null && root.key < tmpnode.par.key)
            tmpnode.par.left = tmpnode;
        else
        {
            if (tmpnode.par != null)
                tmpnode.par.right = tmpnode;
        }
 
        root = tmpnode;
 
        UpdateHeight(root.left);
        UpdateHeight(root.right);
        UpdateHeight(root);
        UpdateHeight(root.par);
 
        return root;
    }
 
    // Function to handle Right Right Case
    public static AVLwithparent RRR(AVLwithparent root)
    {
        AVLwithparent tmpnode = root.right;
 
        root.right = tmpnode.left;
 
        if (tmpnode.left != null)
            tmpnode.left.par = root;
 
        tmpnode.left = root;
 
        tmpnode.par = root.par;
 
        if (tmpnode.par != null && root.key < tmpnode.par.key)
            tmpnode.par.left = tmpnode;
        else
        {
            if (tmpnode.par != null)
                tmpnode.par.right = tmpnode;
        }
 
        root = tmpnode;
 
        UpdateHeight(root.left);
        UpdateHeight(root.right);
        UpdateHeight(root);
        UpdateHeight(root.par);
 
        return root;
    }
 
    // Function to handle Left Right Case
    public static AVLwithparent LRR(AVLwithparent root)
    {
        root.left = RRR(root.left);
        return LLR(root);
    }
 
    // Function to handle right left case
    public static AVLwithparent RLR(AVLwithparent root)
    {
        root.right = LLR(root.right);
        return RRR(root);
    }
 
    // Function to insert a node in the AVL tree
    public static AVLwithparent Insert(AVLwithparent root, AVLwithparent parent, int key)
    {
        if (root == null)
        {
            root = new AVLwithparent();
            root.height = 1;
            root.left = null;
            root.right = null;
            root.par = parent;
            root.key = key;
        }
        else if (root.key > key)
        {
            root.left = Insert(root.left, root, key);
 
            int firstHeight = 0;
            int secondHeight = 0;
 
            if (root.left != null)
                firstHeight = root.left.height;
 
            if (root.right != null)
                secondHeight = root.right.height;
 
            if (Math.Abs(firstHeight - secondHeight) == 2)
            {
                if (root.left != null && key < root.left.key)
                    root = LLR(root);
                else
                    root = LRR(root);
            }
        }
        else if (root.key < key)
        {
            root.right = Insert(root.right, root, key);
 
            int firstHeight = 0;
            int secondHeight = 0;
 
            if (root.left != null)
                firstHeight = root.left.height;
 
            if (root.right != null)
                secondHeight = root.right.height;
 
            if (Math.Abs(firstHeight - secondHeight) == 2)
            {
                if (root.right != null && key < root.right.key)
                    root = RLR(root);
                else
                    root = RRR(root);
            }
        }
 
        UpdateHeight(root);
 
        return root;
    }
 
    // Function to find a key in AVL tree
    public static bool AVLSearch(AVLwithparent root, int key)
    {
        if (root == null)
            return false;
        else if (root.key == key)
            return true;
        else if (root.key > key)
            return AVLSearch(root.left, key);
        else
            return AVLSearch(root.right, key);
    }
 
    // Driver Code
    public static void Main(string[] args)
    {
        AVLwithparent root = null;
 
        root = Insert(root, null, 10);
        root = Insert(root, null, 20);
        root = Insert(root, null, 30);
        root = Insert(root, null, 40);
        root = Insert(root, null, 50);
        root = Insert(root, null, 25);
 
        bool found = AVLSearch(root, 40);
 
        if (found)
            Console.WriteLine("Value found");
        else
            Console.WriteLine("Value not found");
    }
}


Javascript




class AVLwithparent {
    constructor(key, parent = null) {
        this.left = null;
        this.right = null;
        this.key = key;
        this.par = parent; // 'par' keeps track of the parent node
        this.height = 1; // Height of the node initialized to 1
    }
}
 
// Function to update the height of a node
function updateHeight(root) {
    if (root !== null) {
        let val = 1;
 
        if (root.left !== null) {
            val = root.left.height + 1; // Update height considering the left subtree
        }
 
        if (root.right !== null) {
            val = Math.max(val, root.right.height + 1); // Update height considering the right subtree
        }
 
        root.height = val; // Update the height of the current node
    }
}
 
// Left-Left Rotation (LLR)
function llr(root) {
    let tmpNode = root.left;
 
    root.left = tmpNode.right;
    if (tmpNode.right !== null) {
        tmpNode.right.par = root;
    }
 
    tmpNode.right = root;
    tmpNode.par = root.par;
    root.par = tmpNode;
 
    if (tmpNode.par !== null && root.key < tmpNode.par.key) {
        tmpNode.par.left = tmpNode;
    } else {
        if (tmpNode.par !== null) {
            tmpNode.par.right = tmpNode;
        }
    }
 
    root = tmpNode;
 
    // Update heights after rotation
    updateHeight(root.left);
    updateHeight(root.right);
    updateHeight(root);
    updateHeight(root.par);
 
    return root;
}
 
// Right-Right Rotation (RRR)
function rrr(root) {
    let tmpNode = root.right;
 
    root.right = tmpNode.left;
    if (tmpNode.left !== null) {
        tmpNode.left.par = root;
    }
 
    tmpNode.left = root;
    tmpNode.par = root.par;
    root.par = tmpNode;
 
    if (tmpNode.par !== null && root.key < tmpNode.par.key) {
        tmpNode.par.left = tmpNode;
    } else {
        if (tmpNode.par !== null) {
            tmpNode.par.right = tmpNode;
        }
    }
 
    root = tmpNode;
 
    // Update heights after rotation
    updateHeight(root.left);
    updateHeight(root.right);
    updateHeight(root);
    updateHeight(root.par);
 
    return root;
}
 
// Left-Right Rotation (LRR)
function lrr(root) {
    root.left = rrr(root.left);
    return llr(root);
}
 
// Right-Left Rotation (RLR)
function rlr(root) {
    root.right = llr(root.right);
    return rrr(root);
}
 
// Function to insert a node into the AVL tree
function insert(root, parent, key) {
    if (root === null) {
        root = new AVLwithparent(key, parent);
    } else {
        if (root.key > key) {
            root.left = insert(root.left, root, key);
            // Perform rotations if necessary after insertion
            let firstHeight = root.left ? root.left.height : 0;
            let secondHeight = root.right ? root.right.height : 0;
 
            if (Math.abs(firstHeight - secondHeight) === 2) {
                if (root.left !== null && key < root.left.key) {
                    root = llr(root);
                } else {
                    root = lrr(root);
                }
            }
        } else if (root.key < key) {
            root.right = insert(root.right, root, key);
            // Perform rotations if necessary after insertion
            let firstHeight = root.left ? root.left.height : 0;
            let secondHeight = root.right ? root.right.height : 0;
 
            if (Math.abs(firstHeight - secondHeight) === 2) {
                if (root.right !== null && key < root.right.key) {
                    root = rlr(root);
                } else {
                    root = rrr(root);
                }
            }
        }
    }
 
    updateHeight(root); // Update the height of the current node
    return root;
}
 
// Function to search for a node in the AVL tree
function avlSearch(root, key) {
    if (root === null) {
        return false;
    } else if (root.key === key) {
        return true;
    } else if (root.key > key) {
        return avlSearch(root.left, key);
    } else {
        return avlSearch(root.right, key);
    }
}
 
// Driver Code
let root = null;
 
// Inserting nodes into the AVL tree
root = insert(root, null, 10);
root = insert(root, null, 20);
root = insert(root, null, 30);
root = insert(root, null, 40);
root = insert(root, null, 50);
root = insert(root, null, 25);
 
// Searching for a value in the AVL tree
let found = avlSearch(root, 40);
if (found) {
    console.log("Value found");
} else {
    console.log("Value not found");
}


Output

value found




















Time Complexity: O(log N), where N is the number of nodes of the tree
Auxiliary Space: O(1)

Delete Operation: The deletion procedure is similar to that of a normal AVL tree without a parent pointer, but in this case, the references to the parent pointers need to be updated with every deletion and rotation accordingly. Follow the steps below to perform the delete operation:

  • Perform the delete procedure as in a normal BST.
  • From the node that has been deleted, move towards the root.
  • At each node on the path, update the height of the node.
  • Check for AVL conditions at each node. Let there be 3 nodes: w, x, y where w is the current node, x is the root of the subtree of w which has greater height and y is the root of the subtree of x which has greater height.
  • If the node w is unbalanced, there exists one of the following 4 cases:
    • Left Left Case (x is left child of w and y is left child of x)
    • Left Right Case (x is left child of w and y is right child of x)
    • Right Left Case (x is right child of w and y is left child of x)
    • Right Right Case (x is right child of w and y is right child of x)

Below is the implementation of the above approach:

C++




// C++ program for the above approach
#include <bits/stdc++.h>
using namespace std;
 
// AVL tree node
struct AVLwithparent {
    struct AVLwithparent* left;
    struct AVLwithparent* right;
    int key;
    struct AVLwithparent* par;
    int height;
};
 
// Function to print the preorder
// traversal of the AVL tree
void printpreorder(struct AVLwithparent* root)
{
    // Print the node's value along
    // with its parent value
    cout << "Node: " << root->key
         << ", Parent Node: ";
 
    if (root->par != NULL)
        cout << root->par->key << endl;
    else
        cout << "NULL" << endl;
 
    // Recur to the left subtree
    if (root->left != NULL) {
        printpreorder(root->left);
    }
 
    // Recur to the right subtree
    if (root->right != NULL) {
        printpreorder(root->right);
    }
}
 
// Function to update the height of
// a node according to its children's
// node's heights
void Updateheight(
    struct AVLwithparent* root)
{
    if (root != NULL) {
 
        // Store the height of the
        // current node
        int val = 1;
 
        // Store the height of the left
        // and right subtree
        if (root->left != NULL)
            val = root->left->height + 1;
 
        if (root->right != NULL)
            val = max(
                val, root->right->height + 1);
 
        // Update the height of the
        // current node
        root->height = val;
    }
}
 
// Function to handle Left Left Case
struct AVLwithparent* LLR(
    struct AVLwithparent* root)
{
    // Create a reference to the
    // left child
    struct AVLwithparent* tmpnode = root->left;
 
    // Update the left child of the
    // root to the right child of the
    // current left child of the root
    root->left = tmpnode->right;
 
    // Update parent pointer of left
    // child of the root node
    if (tmpnode->right != NULL)
        tmpnode->right->par = root;
 
    // Update the right child of
    // tmpnode to root
    tmpnode->right = root;
 
    // Update parent pointer of tmpnode
    tmpnode->par = root->par;
 
    // Update the parent pointer of root
    root->par = tmpnode;
 
    // Update tmpnode as the left or
    // the right child of its parent
    // pointer according to its key value
    if (tmpnode->par != NULL
        && root->key < tmpnode->par->key) {
        tmpnode->par->left = tmpnode;
    }
    else {
        if (tmpnode->par != NULL)
            tmpnode->par->right = tmpnode;
    }
 
    // Make tmpnode as the new root
    root = tmpnode;
 
    // Update the heights
    Updateheight(root->left);
    Updateheight(root->right);
    Updateheight(root);
    Updateheight(root->par);
 
    // Return the root node
    return root;
}
 
// Function to handle Right Right Case
struct AVLwithparent* RRR(
    struct AVLwithparent* root)
{
    // Create a reference to the
    // right child
    struct AVLwithparent* tmpnode = root->right;
 
    // Update the right child of the
    // root as the left child of the
    // current right child of the root
    root->right = tmpnode->left;
 
    // Update parent pointer of the
    // right child of the root node
    if (tmpnode->left != NULL)
        tmpnode->left->par = root;
 
    // Update the left child of the
    // tmpnode to root
    tmpnode->left = root;
 
    // Update parent pointer of tmpnode
    tmpnode->par = root->par;
 
    // Update the parent pointer of root
    root->par = tmpnode;
 
    // Update tmpnode as the left or
    // the right child of its parent
    // pointer according to its key value
    if (tmpnode->par != NULL
        && root->key < tmpnode->par->key) {
        tmpnode->par->left = tmpnode;
    }
    else {
        if (tmpnode->par != NULL)
            tmpnode->par->right = tmpnode;
    }
 
    // Make tmpnode as the new root
    root = tmpnode;
 
    // Update the heights
    Updateheight(root->left);
    Updateheight(root->right);
    Updateheight(root);
    Updateheight(root->par);
 
    // Return the root node
    return root;
}
 
// Function to handle Left Right Case
struct AVLwithparent* LRR(
    struct AVLwithparent* root)
{
    root->left = RRR(root->left);
    return LLR(root);
}
 
// Function to handle right left case
struct AVLwithparent* RLR(
    struct AVLwithparent* root)
{
    root->right = LLR(root->right);
    return RRR(root);
}
 
// Function to balance the tree after
// deletion of a node
struct AVLwithparent* Balance(
    struct AVLwithparent* root)
{
    // Store the current height of
    // the left and right subtree
    int firstheight = 0;
    int secondheight = 0;
 
    if (root->left != NULL)
        firstheight = root->left->height;
 
    if (root->right != NULL)
        secondheight = root->right->height;
 
    // If current node is not balanced
    if (abs(firstheight - secondheight) == 2) {
        if (firstheight < secondheight) {
 
            // Store the height of the
            // left and right subtree
            // of the current node's
            // right subtree
            int rightheight1 = 0;
            int rightheight2 = 0;
            if (root->right->right != NULL)
                rightheight2 = root->right->right->height;
 
            if (root->right->left != NULL)
                rightheight1 = root->right->left->height;
 
            if (rightheight1 > rightheight2) {
 
                // Right Left Case
                root = RLR(root);
            }
            else {
 
                // Right Right Case
                root = RRR(root);
            }
        }
        else {
 
            // Store the height of the
            // left and right subtree
            // of the current node's
            // left subtree
            int leftheight1 = 0;
            int leftheight2 = 0;
            if (root->left->right != NULL)
                leftheight2 = root->left->right->height;
 
            if (root->left->left != NULL)
                leftheight1 = root->left->left->height;
 
            if (leftheight1 > leftheight2) {
 
                // Left Left Case
                root = LLR(root);
            }
            else {
 
                // Left Right Case
                root = LRR(root);
            }
        }
    }
 
    // Return the root node
    return root;
}
 
// Function to insert a node in
// the AVL tree
struct AVLwithparent* Insert(
    struct AVLwithparent* root,
    struct AVLwithparent* parent,
    int key)
{
 
    if (root == NULL) {
 
        // Create and assign values
        // to a new node
        root = new struct AVLwithparent;
        if (root == NULL)
            cout << "Error in memory" << endl;
        else {
            root->height = 1;
            root->left = NULL;
            root->right = NULL;
            root->par = parent;
            root->key = key;
        }
    }
 
    else if (root->key > key) {
 
        // Recur to the left subtree
        // to insert the node
        root->left = Insert(root->left,
                            root, key);
 
        // Store the heights of the
        // left and right subtree
        int firstheight = 0;
        int secondheight = 0;
 
        if (root->left != NULL)
            firstheight = root->left->height;
 
        if (root->right != NULL)
            secondheight = root->right->height;
 
        // Balance the tree if the
        // current node is not balanced
        if (abs(firstheight
                - secondheight)
            == 2) {
 
            if (root->left != NULL
                && key < root->left->key) {
 
                // Left Left Case
                root = LLR(root);
            }
            else {
 
                // Left Right Case
                root = LRR(root);
            }
        }
    }
 
    else if (root->key < key) {
 
        // Recur to the right subtree
        // to insert the node
        root->right = Insert(root->right,
                             root, key);
 
        // Store the heights of the left
        // and right subtree
        int firstheight = 0;
        int secondheight = 0;
 
        if (root->left != NULL)
            firstheight = root->left->height;
 
        if (root->right != NULL)
            secondheight = root->right->height;
 
        // Balance the tree if the
        // current node is not balanced
        if (abs(firstheight - secondheight) == 2) {
            if (root->right != NULL
                && key < root->right->key) {
 
                // Right Left Case
                root = RLR(root);
            }
            else {
 
                // Right Right Case
                root = RRR(root);
            }
        }
    }
 
    // Case when given key is
    // already in tree
    else {
    }
 
    // Update the height of the
    // root node
    Updateheight(root);
 
    // Return the root node
    return root;
}
 
// Function to delete a node from
// the AVL tree
struct AVLwithparent* Delete(
    struct AVLwithparent* root,
    int key)
{
    if (root != NULL) {
 
        // If the node is found
        if (root->key == key) {
 
            // Replace root with its
            // left child
            if (root->right == NULL
                && root->left != NULL) {
                if (root->par != NULL) {
                    if (root->par->key
                        < root->key)
                        root->par->right = root->left;
                    else
                        root->par->left = root->left;
 
                    // Update the height
                    // of root's parent
                    Updateheight(root->par);
                }
 
                root->left->par = root->par;
 
                // Balance the node
                // after deletion
                root->left = Balance(
                    root->left);
 
                return root->left;
            }
 
            // Replace root with its
            // right child
            else if (root->left == NULL
                     && root->right != NULL) {
                if (root->par != NULL) {
                    if (root->par->key
                        < root->key)
                        root->par->right = root->right;
                    else
                        root->par->left = root->right;
 
                    // Update the height
                    // of the root's parent
                    Updateheight(root->par);
                }
 
                root->right->par = root->par;
 
                // Balance the node after
                // deletion
                root->right = Balance(root->right);
                return root->right;
            }
 
            // Remove the references of
            // the current node
            else if (root->left == NULL
                     && root->right == NULL) {
                if (root->par->key < root->key) {
                    root->par->right = NULL;
                }
                else {
                    root->par->left = NULL;
                }
 
                if (root->par != NULL)
                    Updateheight(root->par);
 
                root = NULL;
                return NULL;
            }
 
            // Otherwise, replace the
            // current node with its
            // successor and then
            // recursively call Delete()
            else {
                struct AVLwithparent* tmpnode = root;
                tmpnode = tmpnode->right;
                while (tmpnode->left != NULL) {
                    tmpnode = tmpnode->left;
                }
 
                int val = tmpnode->key;
 
                root->right
                    = Delete(root->right, tmpnode->key);
 
                root->key = val;
 
                // Balance the node
                // after deletion
                root = Balance(root);
            }
        }
 
        // Recur to the right subtree to
        // delete the current node
        else if (root->key < key) {
            root->right = Delete(root->right, key);
 
            root = Balance(root);
        }
 
        // Recur into the right subtree
        // to delete the current node
        else if (root->key > key) {
            root->left = Delete(root->left, key);
 
            root = Balance(root);
        }
 
        // Update height of the root
        if (root != NULL) {
            Updateheight(root);
        }
    }
 
    // Handle the case when the key to be
    // deleted could not be found
    else {
        cout << "Key to be deleted "
             << "could not be found\n";
    }
 
    // Return the root node
    return root;
}
 
// Driver Code
int main()
{
    struct AVLwithparent* root;
    root = NULL;
 
    // Function call to insert the nodes
    root = Insert(root, NULL, 9);
    root = Insert(root, NULL, 5);
    root = Insert(root, NULL, 10);
    root = Insert(root, NULL, 0);
    root = Insert(root, NULL, 6);
 
    // Print the tree before deleting node
    cout << "Before deletion:\n";
    printpreorder(root);
 
    // Function Call to delete node 10
    root = Delete(root, 10);
 
    // Print the tree after deleting node
    cout << "After deletion:\n";
    printpreorder(root);
}


Java




// Java program for the above approach
class AVLwithparent {
    AVLwithparent left, right, par;
    int key, height;
 
    AVLwithparent(int item) {
        key = item;
        height = 1;
    }
}
 
public class AVLTreeWithParent {
 
    // Function to print the preorder
    // traversal of the AVL tree
    static void printPreorder(AVLwithparent root) {
        if (root != null) {
            // Print the node's value along
            // with its parent value
            System.out.print("Node: " + root.key + ", Parent Node: ");
 
            if (root.par != null)
                System.out.println(root.par.key);
            else
                System.out.println("NULL");
 
            // Recur to the left subtree
            printPreorder(root.left);
 
            // Recur to the right subtree
            printPreorder(root.right);
        }
    }
 
    // Function to update the height of
    // a node according to its children's
    // node's heights
    static void updateHeight(AVLwithparent root) {
        if (root != null) {
            // Store the height of the
            // current node
            int val = 1;
 
            // Store the height of the left
            // and right subtree
            if (root.left != null)
                val = root.left.height + 1;
 
            if (root.right != null)
                val = Math.max(val, root.right.height + 1);
 
            // Update the height of the
            // current node
            root.height = val;
        }
    }
 
    // Function to handle Left Left Case
    static AVLwithparent LLR(AVLwithparent root) {
        // Create a reference to the
        // left child
        AVLwithparent tmpnode = root.left;
 
        // Update the left child of the
        // root to the right child of the
        // current left child of the root
        root.left = tmpnode.right;
 
        // Update parent pointer of left
        // child of the root node
        if (tmpnode.right != null)
            tmpnode.right.par = root;
 
        // Update the right child of
        // tmpnode to root
        tmpnode.right = root;
 
        // Update parent pointer of tmpnode
        tmpnode.par = root.par;
 
        // Update the parent pointer of root
        if (tmpnode.par != null && root.key < tmpnode.par.key)
            tmpnode.par.left = tmpnode;
        else {
            if (tmpnode.par != null)
                tmpnode.par.right = tmpnode;
        }
 
        // Make tmpnode as the new root
        root = tmpnode;
 
        // Update the heights
        updateHeight(root.left);
        updateHeight(root.right);
        updateHeight(root);
        updateHeight(root.par);
 
        // Return the root node
        return root;
    }
 
    // Function to handle Right Right Case
    static AVLwithparent RRR(AVLwithparent root) {
        // Create a reference to the
        // right child
        AVLwithparent tmpnode = root.right;
 
        // Update the right child of the
        // root as the left child of the
        // current right child of the root
        root.right = tmpnode.left;
 
        // Update parent pointer of the
        // right child of the root node
        if (tmpnode.left != null)
            tmpnode.left.par = root;
 
        // Update the left child of the
        // tmpnode to root
        tmpnode.left = root;
 
        // Update parent pointer of tmpnode
        tmpnode.par = root.par;
 
        // Update the parent pointer of root
        if (tmpnode.par != null && root.key < tmpnode.par.key)
            tmpnode.par.left = tmpnode;
        else {
            if (tmpnode.par != null)
                tmpnode.par.right = tmpnode;
        }
 
        // Make tmpnode as the new root
        root = tmpnode;
 
        // Update the heights
        updateHeight(root.left);
        updateHeight(root.right);
        updateHeight(root);
        updateHeight(root.par);
 
        // Return the root node
        return root;
    }
 
    // Function to handle Left Right Case
    static AVLwithparent LRR(AVLwithparent root) {
        root.left = RRR(root.left);
        return LLR(root);
    }
 
    // Function to handle right left case
    static AVLwithparent RLR(AVLwithparent root) {
        root.right = LLR(root.right);
        return RRR(root);
    }
 
    // Function to balance the tree after
    // deletion of a node
    static AVLwithparent balance(AVLwithparent root) {
        // Store the current height of
        // the left and right subtree
        int firstheight = 0;
        int secondheight = 0;
 
        if (root.left != null)
            firstheight = root.left.height;
 
        if (root.right != null)
            secondheight = root.right.height;
 
        // If current node is not balanced
        if (Math.abs(firstheight - secondheight) == 2) {
            if (firstheight < secondheight) {
                // Store the height of the
                // left and right subtree
                // of the current node's
                // right subtree
                int rightheight1 = 0;
                int rightheight2 = 0;
                if (root.right.right != null)
                    rightheight2 = root.right.right.height;
 
                if (root.right.left != null)
                    rightheight1 = root.right.left.height;
 
                if (rightheight1 > rightheight2) {
                    // Right Left Case
                    root = RLR(root);
                } else {
                    // Right Right Case
                    root = RRR(root);
                }
            } else {
                // Store the height of the
                // left and right subtree
                // of the current node's
                // left subtree
                int leftheight1 = 0;
                int leftheight2 = 0;
                if (root.left.right != null)
                    leftheight2 = root.left.right.height;
 
                if (root.left.left != null)
                    leftheight1 = root.left.left.height;
 
                if (leftheight1 > leftheight2) {
                    // Left Left Case
                    root = LLR(root);
                } else {
                    // Left Right Case
                    root = LRR(root);
                }
            }
        }
 
        // Return the root node
        return root;
    }
 
    // Function to insert a node in
    // the AVL tree
    static AVLwithparent insert(AVLwithparent root, AVLwithparent parent, int key) {
        if (root == null) {
            // Create and assign values
            // to a new node
            root = new AVLwithparent(key);
            if (root == null)
                System.out.println("Error in memory");
            else {
                root.height = 1;
                root.left = null;
                root.right = null;
                root.par = parent;
            }
        } else if (root.key > key) {
            // Recur to the left subtree
            // to insert the node
            root.left = insert(root.left, root, key);
 
            // Store the heights of the
            // left and right subtree
            int firstheight = 0;
            int secondheight = 0;
 
            if (root.left != null)
                firstheight = root.left.height;
 
            if (root.right != null)
                secondheight = root.right.height;
 
            // Balance the tree if the
            // current node is not balanced
            if (Math.abs(firstheight - secondheight) == 2) {
                if (root.left != null && key < root.left.key) {
                    // Left Left Case
                    root = LLR(root);
                } else {
                    // Left Right Case
                    root = LRR(root);
                }
            }
        } else if (root.key < key) {
            // Recur to the right subtree
            // to insert the node
            root.right = insert(root.right, root, key);
 
            // Store the heights of the left
            // and right subtree
            int firstheight = 0;
            int secondheight = 0;
 
            if (root.left != null)
                firstheight = root.left.height;
 
            if (root.right != null)
                secondheight = root.right.height;
 
            // Balance the tree if the
            // current node is not balanced
            if (Math.abs(firstheight - secondheight) == 2) {
                if (root.right != null && key < root.right.key) {
                    // Right Left Case
                    root = RLR(root);
                } else {
                    // Right Right Case
                    root = RRR(root);
                }
            }
        }
 
        // Case when given key is
        // already in tree
        // Do nothing
 
        // Update the height of the
        // root node
        updateHeight(root);
 
        // Return the root node
        return root;
    }
 
    // Function to delete a node from
    // the AVL tree
    static AVLwithparent delete(AVLwithparent root, int key) {
        if (root != null) {
            // If the node is found
            if (root.key == key) {
                // Replace root with its
                // left child
                if (root.right == null && root.left != null) {
                    if (root.par != null) {
                        if (root.par.key < root.key)
                            root.par.right = root.left;
                        else
                            root.par.left = root.left;
 
                        // Update the height
                        // of root's parent
                        updateHeight(root.par);
                    }
 
                    root.left.par = root.par;
 
                    // Balance the node
                    // after deletion
                    root.left = balance(root.left);
                    return root.left;
                }
                // Replace root with its
                // right child
                else if (root.left == null && root.right != null) {
                    if (root.par != null) {
                        if (root.par.key < root.key)
                            root.par.right = root.right;
                        else
                            root.par.left = root.right;
 
                        // Update the height
                        // of the root's parent
                        updateHeight(root.par);
                    }
 
                    root.right.par = root.par;
 
                    // Balance the node after
                    // deletion
                    root.right = balance(root.right);
                    return root.right;
                }
                // Remove the references of
                // the current node
                else if (root.left == null && root.right == null) {
                    if (root.par.key < root.key) {
                        root.par.right = null;
                    } else {
                        root.par.left = null;
                    }
 
                    if (root.par != null)
                        updateHeight(root.par);
 
                    root = null;
                    return null;
                }
                // Otherwise, replace the
                // current node with its
                // successor and then
                // recursively call delete()
                else {
                    AVLwithparent tmpnode = root;
                    tmpnode = tmpnode.right;
                    while (tmpnode.left != null) {
                        tmpnode = tmpnode.left;
                    }
 
                    int val = tmpnode.key;
 
                    root.right = delete(root.right, tmpnode.key);
 
                    root.key = val;
 
                    // Balance the node
                    // after deletion
                    root = balance(root);
                }
            }
 
            // Recur to the right subtree to
            // delete the current node
            else if (root.key < key) {
                root.right = delete(root.right, key);
 
                root = balance(root);
            }
 
            // Recur into the right subtree
            // to delete the current node
            else if (root.key > key) {
                root.left = delete(root.left, key);
 
                root = balance(root);
            }
 
            // Update height of the root
            if (root != null) {
                updateHeight(root);
            }
        }
 
        // Handle the case when the key to be
        // deleted could not be found
        else {
            System.out.println("Key to be deleted could not be found");
        }
 
        // Return the root node
        return root;
    }
 
    // Driver Code
    public static void main(String[] args) {
        AVLwithparent root = null;
 
        // Function call to insert the nodes
        root = insert(root, null, 9);
        root = insert(root, null, 5);
        root = insert(root, null, 10);
        root = insert(root, null, 0);
        root = insert(root, null, 6);
 
        // Print the tree before deleting node
        System.out.println("Before deletion:");
        printPreorder(root);
 
        // Function Call to delete node 10
        root = delete(root, 10);
 
        // Print the tree after deleting node
        System.out.println("After deletion:");
        printPreorder(root);
    }
}


Python3




class AVLwithparent:
    def __init__(self, key, parent=None):
        self.left = None
        self.right = None
        self.key = key
        self.par = parent
        self.height = 1
 
 
def print_preorder(root):
    if root:
        print("Node:", root.key, ", Parent Node:", root.par.key if root.par else "NULL")
        print_preorder(root.left)
        print_preorder(root.right)
 
 
def update_height(root):
    if root:
        val = 1
        if root.left:
            val = root.left.height + 1
        if root.right:
            val = max(val, root.right.height + 1)
        root.height = val
 
 
def llr(root):
    tmp_node = root.left
    root.left = tmp_node.right
    if tmp_node.right:
        tmp_node.right.par = root
    tmp_node.right = root
    tmp_node.par = root.par
    root.par = tmp_node
    if tmp_node.par and root.key < tmp_node.par.key:
        tmp_node.par.left = tmp_node
    elif tmp_node.par:
        tmp_node.par.right = tmp_node
    root = tmp_node
    update_height(root.left)
    update_height(root.right)
    update_height(root)
    update_height(root.par)
    return root
 
 
def rrr(root):
    tmp_node = root.right
    root.right = tmp_node.left
    if tmp_node.left:
        tmp_node.left.par = root
    tmp_node.left = root
    tmp_node.par = root.par
    root.par = tmp_node
    if tmp_node.par and root.key < tmp_node.par.key:
        tmp_node.par.left = tmp_node
    elif tmp_node.par:
        tmp_node.par.right = tmp_node
    root = tmp_node
    update_height(root.left)
    update_height(root.right)
    update_height(root)
    update_height(root.par)
    return root
 
 
def lrr(root):
    root.left = rrr(root.left)
    return llr(root)
 
 
def rlr(root):
    root.right = llr(root.right)
    return rrr(root)
 
 
def balance(root):
    first_height = 0
    second_height = 0
    if root.left:
        first_height = root.left.height
    if root.right:
        second_height = root.right.height
    if abs(first_height - second_height) == 2:
        if first_height < second_height:
            rightheight1 = 0
            rightheight2 = 0
            if root.right.right:
                rightheight2 = root.right.right.height
            if root.right.left:
                rightheight1 = root.right.left.height
            if rightheight1 > rightheight2:
                root = rlr(root)
            else:
                root = rrr(root)
        else:
            leftheight1 = 0
            leftheight2 = 0
            if root.left.right:
                leftheight2 = root.left.right.height
            if root.left.left:
                leftheight1 = root.left.left.height
            if leftheight1 > leftheight2:
                root = llr(root)
            else:
                root = lrr(root)
    return root
 
 
def insert(root, parent, key):
    if root is None:
        root = AVLwithparent(key, parent)
    elif root.key > key:
        root.left = insert(root.left, root, key)
        first_height = 0
        second_height = 0
        if root.left:
            first_height = root.left.height
        if root.right:
            second_height = root.right.height
        if abs(first_height - second_height) == 2:
            if root.left and key < root.left.key:
                root = llr(root)
            else:
                root = lrr(root)
    elif root.key < key:
        root.right = insert(root.right, root, key)
        first_height = 0
        second_height = 0
        if root.left:
            first_height = root.left.height
        if root.right:
            second_height = root.right.height
        if abs(first_height - second_height) == 2:
            if root.right and key < root.right.key:
                root = rlr(root)
            else:
                root = rrr(root)
    update_height(root)
    return root
 
 
def delete(root, key):
    if root:
        if root.key == key:
            if root.right is None and root.left is not None:
                if root.par:
                    if root.par.key < root.key:
                        root.par.right = root.left
                    else:
                        root.par.left = root.left
                    update_height(root.par)
                root.left.par = root.par
                root.left = balance(root.left)
                return root.left
            elif root.left is None and root.right is not None:
                if root.par:
                    if root.par.key < root.key:
                        root.par.right = root.right
                    else:
                        root.par.left = root.right
                    update_height(root.par)
                root.right.par = root.par
                root.right = balance(root.right)
                return root.right
            elif root.left is None and root.right is None:
                if root.par:
                    if root.par.key < root.key:
                        root.par.right = None
                    else:
                        root.par.left = None
                    update_height(root.par)
                root = None
                return None
            else:
                tmp_node = root
                tmp_node = tmp_node.right
                while tmp_node.left:
                    tmp_node = tmp_node.left
                val = tmp_node.key
                root.right = delete(root.right, tmp_node.key)
                root.key = val
                root = balance(root)
        elif root.key < key:
            root.right = delete(root.right, key)
            root = balance(root)
        elif root.key > key:
            root.left = delete(root.left, key)
            root = balance(root)
        update_height(root)
    return root
 
 
# Driver Code
if __name__ == "__main__":
    root = None
 
    # Function call to insert the nodes
    root = insert(root, None, 9)
    root = insert(root, None, 5)
    root = insert(root, None, 10)
    root = insert(root, None, 0)
    root = insert(root, None, 6)
 
    # Print the tree before deleting node
    print("Before deletion:")
    print_preorder(root)
 
    # Function Call to delete node 10
    root = delete(root, 10)
 
    # Print the tree after deleting node
    print("After deletion:")
    print_preorder(root)


C#




using System;
 
// AVL tree node
public class AVLwithparent
{
    public AVLwithparent left;
    public AVLwithparent right;
    public AVLwithparent par;
    public int key;
    public int height;
 
    public AVLwithparent(int key)
    {
        this.key = key;
        this.height = 1;
    }
}
 
public class AVLTreeWithParent
{
    // Function to print the preorder traversal of the AVL tree
    public static void PrintPreorder(AVLwithparent root)
    {
        if (root != null)
        {
            // Print the node's value along with its parent value
            Console.Write("Node: " + root.key + ", Parent Node: ");
            if (root.par != null)
                Console.WriteLine(root.par.key);
            else
                Console.WriteLine("NULL");
 
            // Recur to the left subtree
            PrintPreorder(root.left);
 
            // Recur to the right subtree
            PrintPreorder(root.right);
        }
    }
 
    // Function to update the height of a node according to its children's node's heights
    public static void UpdateHeight(AVLwithparent root)
    {
        if (root != null)
        {
            // Store the height of the current node
            int val = 1;
 
            // Store the height of the left and right subtree
            if (root.left != null)
                val = root.left.height + 1;
            if (root.right != null)
                val = Math.Max(val, root.right.height + 1);
 
            // Update the height of the current node
            root.height = val;
        }
    }
 
    // Function to handle Left Left Case
    public static AVLwithparent LLR(AVLwithparent root)
    {
        AVLwithparent tmpnode = root.left;
 
        root.left = tmpnode.right;
        if (tmpnode.right != null)
            tmpnode.right.par = root;
 
        tmpnode.right = root;
        tmpnode.par = root.par;
 
        if (tmpnode.par != null && root.key < tmpnode.par.key)
            tmpnode.par.left = tmpnode;
        else
        {
            if (tmpnode.par != null)
                tmpnode.par.right = tmpnode;
        }
 
        root.par = tmpnode;
 
        root = tmpnode;
 
        UpdateHeight(root.left);
        UpdateHeight(root.right);
        UpdateHeight(root);
        UpdateHeight(root.par);
 
        return root;
    }
 
    // Function to handle Right Right Case
    public static AVLwithparent RRR(AVLwithparent root)
    {
        AVLwithparent tmpnode = root.right;
 
        root.right = tmpnode.left;
        if (tmpnode.left != null)
            tmpnode.left.par = root;
 
        tmpnode.left = root;
        tmpnode.par = root.par;
 
        if (tmpnode.par != null && root.key < tmpnode.par.key)
            tmpnode.par.left = tmpnode;
        else
        {
            if (tmpnode.par != null)
                tmpnode.par.right = tmpnode;
        }
 
        root.par = tmpnode;
 
        root = tmpnode;
 
        UpdateHeight(root.left);
        UpdateHeight(root.right);
        UpdateHeight(root);
        UpdateHeight(root.par);
 
        return root;
    }
 
    // Function to handle Left Right Case
    public static AVLwithparent LRR(AVLwithparent root)
    {
        root.left = RRR(root.left);
        return LLR(root);
    }
 
    // Function to handle right left case
    public static AVLwithparent RLR(AVLwithparent root)
    {
        root.right = LLR(root.right);
        return RRR(root);
    }
 
    // Function to balance the tree after deletion of a node
    public static AVLwithparent Balance(AVLwithparent root)
    {
        int firstheight = 0;
        int secondheight = 0;
 
        if (root.left != null)
            firstheight = root.left.height;
 
        if (root.right != null)
            secondheight = root.right.height;
 
        if (Math.Abs(firstheight - secondheight) == 2)
        {
            if (firstheight < secondheight)
            {
                int rightheight1 = 0;
                int rightheight2 = 0;
                if (root.right.right != null)
                    rightheight2 = root.right.right.height;
 
                if (root.right.left != null)
                    rightheight1 = root.right.left.height;
 
                if (rightheight1 > rightheight2)
                    root = RLR(root);
                else
                    root = RRR(root);
            }
            else
            {
                int leftheight1 = 0;
                int leftheight2 = 0;
                if (root.left.right != null)
                    leftheight2 = root.left.right.height;
 
                if (root.left.left != null)
                    leftheight1 = root.left.left.height;
 
                if (leftheight1 > leftheight2)
                    root = LLR(root);
                else
                    root = LRR(root);
            }
        }
 
        return root;
    }
 
    // Function to insert a node in the AVL tree
    public static AVLwithparent Insert(AVLwithparent root, AVLwithparent parent, int key)
    {
        if (root == null)
        {
            root = new AVLwithparent(key);
            root.par = parent;
        }
        else if (root.key > key)
        {
            root.left = Insert(root.left, root, key);
            if (Math.Abs((root.left != null ? root.left.height : 0) - (root.right != null ? root.right.height : 0)) == 2)
            {
                if (root.left != null && key < root.left.key)
                    root = LLR(root);
                else
                    root = LRR(root);
            }
        }
        else if (root.key < key)
        {
            root.right = Insert(root.right, root, key);
            if (Math.Abs((root.left != null ? root.left.height : 0) - (root.right != null ? root.right.height : 0)) == 2)
            {
                if (root.right != null && key < root.right.key)
                    root = RLR(root);
                else
                    root = RRR(root);
            }
        }
 
        UpdateHeight(root);
        return root;
    }
 
    // Function to delete a node from the AVL tree
    public static AVLwithparent Delete(AVLwithparent root, int key)
    {
        if (root != null)
        {
            if (root.key == key)
            {
                if (root.right == null && root.left != null)
                {
                    if (root.par != null)
                    {
                        if (root.par.key < root.key)
                            root.par.right = root.left;
                        else
                            root.par.left = root.left;
 
                        UpdateHeight(root.par);
                    }
 
                    root.left.par = root.par;
                    root.left = Balance(root.left);
                    return root.left;
                }
                else if (root.left == null && root.right != null)
                {
                    if (root.par != null)
                    {
                        if (root.par.key < root.key)
                            root.par.right = root.right;
                        else
                            root.par.left = root.right;
 
                        UpdateHeight(root.par);
                    }
 
                    root.right.par = root.par;
                    root.right = Balance(root.right);
                    return root.right;
                }
                else if (root.left == null && root.right == null)
                {
                    if (root.par != null)
                    {
                        if (root.par.key < root.key)
                            root.par.right = null;
                        else
                            root.par.left = null;
 
                        UpdateHeight(root.par);
                    }
 
                    root = null;
                    return null;
                }
                else
                {
                    AVLwithparent tmpnode = root.right;
                    while (tmpnode.left != null)
                        tmpnode = tmpnode.left;
 
                    int val = tmpnode.key;
                    root.right = Delete(root.right, tmpnode.key);
                    root.key = val;
                    root = Balance(root);
                }
            }
            else if (root.key < key)
            {
                root.right = Delete(root.right, key);
                root = Balance(root);
            }
            else if (root.key > key)
            {
                root.left = Delete(root.left, key);
                root = Balance(root);
            }
 
            UpdateHeight(root);
        }
        else
            Console.WriteLine("Key to be deleted could not be found");
 
        return root;
    }
 
    // Driver Code
    public static void Main(string[] args)
    {
        AVLwithparent root = null;
 
        // Function call to insert the nodes
        root = Insert(root, null, 9);
        root = Insert(root, null, 5);
        root = Insert(root, null, 10);
        root = Insert(root, null, 0);
        root = Insert(root, null, 6);
 
        // Print the tree before deleting node
        Console.WriteLine("Before deletion:");
        PrintPreorder(root);
 
        // Function Call to delete node 10
        root = Delete(root, 10);
 
        // Print the tree after deleting node
        Console.WriteLine("After deletion:");
        PrintPreorder(root);
    }
}
//This code is contributed by Utkarsh


Javascript




// AVL tree node
class AVLwithparent {
    constructor(key) {
        this.left = null;
        this.right = null;
        this.key = key;
        this.par = null;
        this.height = 1;
    }
}
 
// Function to print the preorder traversal of the AVL tree
function printpreorder(root) {
    if (root !== null) {
        // Print the node's value along with its parent value
        console.log(`Node: ${root.key}, Parent Node: ${root.par ? root.par.key : 'NULL'}`);
 
        // Recur to the left subtree
        printpreorder(root.left);
 
        // Recur to the right subtree
        printpreorder(root.right);
    }
}
 
// Function to update the height of a node according to its children's node's heights
function Updateheight(root) {
    if (root !== null) {
        // Store the height of the current node
        let val = 1;
 
        // Store the height of the left and right subtree
        if (root.left !== null) {
            val = root.left.height + 1;
        }
 
        if (root.right !== null) {
            val = Math.max(val, root.right.height + 1);
        }
 
        // Update the height of the current node
        root.height = val;
    }
}
 
// Function to handle Left Left Case
function LLR(root) {
    // Create a reference to the left child
    const tmpnode = root.left;
 
    // Update the left child of the root to the right child of the current left child of the root
    root.left = tmpnode.right;
 
    // Update parent pointer of left child of the root node
    if (tmpnode.right !== null) {
        tmpnode.right.par = root;
    }
 
    // Update the right child of tmpnode to root
    tmpnode.right = root;
 
    // Update parent pointer of tmpnode
    tmpnode.par = root.par;
 
    // Update the parent pointer of root
    root.par = tmpnode;
 
    // Update tmpnode as the left or the right child of its parent pointer according to its key value
    if (tmpnode.par !== null && root.key < tmpnode.par.key) {
        tmpnode.par.left = tmpnode;
    } else {
        if (tmpnode.par !== null) {
            tmpnode.par.right = tmpnode;
        }
    }
 
    // Make tmpnode as the new root
    root = tmpnode;
 
    // Update the heights
    Updateheight(root.left);
    Updateheight(root.right);
    Updateheight(root);
    Updateheight(root.par);
 
    // Return the root node
    return root;
}
 
// Function to handle Right Right Case
function RRR(root) {
    // Create a reference to the right child
    const tmpnode = root.right;
 
    // Update the right child of the root as the left child of the current right child of the root
    root.right = tmpnode.left;
 
    // Update parent pointer of the right child of the root node
    if (tmpnode.left !== null) {
        tmpnode.left.par = root;
    }
 
    // Update the left child of the tmpnode to root
    tmpnode.left = root;
 
    // Update parent pointer of tmpnode
    tmpnode.par = root.par;
 
    // Update the parent pointer of root
    root.par = tmpnode;
 
    // Update tmpnode as the left or the right child of its parent pointer according to its key value
    if (tmpnode.par !== null && root.key < tmpnode.par.key) {
        tmpnode.par.left = tmpnode;
    } else {
        if (tmpnode.par !== null) {
            tmpnode.par.right = tmpnode;
        }
    }
 
    // Make tmpnode as the new root
    root = tmpnode;
 
    // Update the heights
    Updateheight(root.left);
    Updateheight(root.right);
    Updateheight(root);
    Updateheight(root.par);
 
    // Return the root node
    return root;
}
 
// Function to handle Left Right Case
function LRR(root) {
    root.left = RRR(root.left);
    return LLR(root);
}
 
// Function to handle Right Left Case
function RLR(root) {
    root.right = LLR(root.right);
    return RRR(root);
}
 
// Function to Balance the tree after deletion of a node
function Balance(root) {
    // Store the current height of the left and right subtree
    let firstheight = 0;
    let secondheight = 0;
 
    if (root.left !== null) {
        firstheight = root.left.height;
    }
 
    if (root.right !== null) {
        secondheight = root.right.height;
    }
 
    // If the current node is not Balanced
    if (Math.abs(firstheight - secondheight) === 2) {
        if (firstheight < secondheight) {
            // Store the height of the left and right subtree of the current node's right subtree
            let rightheight1 = 0;
            let rightheight2 = 0;
            if (root.right.right !== null) {
                rightheight2 = root.right.right.height;
            }
 
            if (root.right.left !== null) {
                rightheight1 = root.right.left.height;
            }
 
            if (rightheight1 > rightheight2) {
                // Right Left Case
                root = RLR(root);
            } else {
                // Right Right Case
                root = RRR(root);
            }
        } else {
            // Store the height of the left and right subtree of the current node's left subtree
            let leftheight1 = 0;
            let leftheight2 = 0;
            if (root.left.right !== null) {
                leftheight2 = root.left.right.height;
            }
 
            if (root.left.left !== null) {
                leftheight1 = root.left.left.height;
            }
 
            if (leftheight1 > leftheight2) {
                // Left Left Case
                root = LLR(root);
            } else {
                // Left Right Case
                root = LRR(root);
            }
        }
    }
 
    // Return the root node
    return root;
}
 
// Function to Insert a node in the AVL tree
function Insert(root, parent, key) {
    if (root === null) {
        // Create and assign values to a new node
        root = new AVLwithparent(key);
        if (root === null) {
            console.log("Error in memory");
        } else {
            root.par = parent;
        }
    } else if (root.key > key) {
        // Recur to the left subtree to Insert the node
        root.left = Insert(root.left, root, key);
 
        // Store the heights of the left and right subtree
        let firstheight = 0;
        let secondheight = 0;
 
        if (root.left !== null) {
            firstheight = root.left.height;
        }
 
        if (root.right !== null) {
            secondheight = root.right.height;
        }
 
        // Balance the tree if the current node is not Balanced
        if (Math.abs(firstheight - secondheight) === 2) {
            if (root.left !== null && key < root.left.key) {
                // Left Left Case
                root = LLR(root);
            } else {
                // Left Right Case
                root = LRR(root);
            }
        }
    } else if (root.key < key) {
        // Recur to the right subtree to Insert the node
        root.right = Insert(root.right, root, key);
 
        // Store the heights of the left and right subtree
        let firstheight = 0;
        let secondheight = 0;
 
        if (root.left !== null) {
            firstheight = root.left.height;
        }
 
        if (root.right !== null) {
            secondheight = root.right.height;
        }
 
        // Balance the tree if the current node is not Balanced
        if (Math.abs(firstheight - secondheight) === 2) {
            if (root.right !== null && key < root.right.key) {
                // Right Left Case
                root = RLR(root);
            } else {
                // Right Right Case
                root = RRR(root);
            }
        }
    }
    // Case when given key is already in tree
    else {
        // Do nothing
    }
 
    // Update the height of the root node
    Updateheight(root);
 
    // Return the root node
    return root;
}
 
// Function to delete a node from the AVL tree
function Delete(root, key) {
    if (root !== null) {
        // If the node is found
        if (root.key === key) {
            // Replace root with its left child
            if (root.right === null && root.left !== null) {
                if (root.par !== null) {
                    if (root.par.key < root.key) {
                        root.par.right = root.left;
                    } else {
                        root.par.left = root.left;
                    }
 
                    // Update the height of root's parent
                    Updateheight(root.par);
                }
 
                root.left.par = root.par;
 
                // Balance the node after deletion
                root.left = Balance(root.left);
                return root.left;
            }
            // Replace root with its right child
            else if (root.left === null && root.right !== null) {
                if (root.par !== null) {
                    if (root.par.key < root.key) {
                        root.par.right = root.right;
                    } else {
                        root.par.left = root.right;
                    }
 
                    // Update the height of the root's parent
                    Updateheight(root.par);
                }
 
                root.right.par = root.par;
 
                // Balance the node after deletion
                root.right = Balance(root.right);
                return root.right;
            }
            // Delete the references of the current node
            else if (root.left === null && root.right === null) {
                if (root.par.key < root.key) {
                    root.par.right = null;
                } else {
                    root.par.left = null;
                }
 
                if (root.par !== null) {
                    Updateheight(root.par);
                }
 
                root = null;
                return null;
            }
            // Otherwise, replace the current node with its successor and then recursively call Delete()
            else {
                let tmpnode = root;
                tmpnode = tmpnode.right;
                while (tmpnode.left !== null) {
                    tmpnode = tmpnode.left;
                }
 
                let val = tmpnode.key;
 
                root.right = Delete(root.right, tmpnode.key);
 
                root.key = val;
 
                // Balance the node after deletion
                root = Balance(root);
            }
        }
        // Recur to the right subtree to delete the current node
        else if (root.key < key) {
            root.right = Delete(root.right, key);
 
            root = Balance(root);
        }
        // Recur into the right subtree to delete the current node
        else if (root.key > key) {
            root.left = Delete(root.left, key);
 
            root = Balance(root);
        }
 
        // Update height of the root
        if (root !== null) {
            Updateheight(root);
        }
    }
    // Handle the case when the key to be deleted could not be found
    else {
        console.log("Key to be deleted could not be found");
    }
 
    // Return the root node
    return root;
}
 
// Driver Code
let root = null;
 
// Function call to Insert the nodes
root = Insert(root, null, 9);
root = Insert(root, null, 5);
root = Insert(root, null, 10);
root = Insert(root, null, 0);
root = Insert(root, null, 6);
 
// Print the tree before deleting node
console.log("Before deletion:");
printpreorder(root);
 
// Function Call to delete node 10
root = Delete(root, 10);
 
// Print the tree after deleting node
console.log("After deletion:");
printpreorder(root);
 
// This Code is contributed by Yash Agarwal(yashagarwal2852002)


Output

Before deletion:
Node: 9, Parent Node: NULL
Node: 5, Parent Node: 9
Node: 0, Parent Node: 5
Node: 6, Parent Node: 5
Node: 10, Parent Node: 9
After deletion:
Node: 6, Parent Node: NULL
Node: 5, Parent ...


Time Complexity: O(log N), where N is the number of nodes of the tree
Auxiliary Space: O(1)



Last Updated : 06 Feb, 2024
Like Article
Save Article
Previous
Next
Share your thoughts in the comments
Similar Reads