Skip to content
Related Articles

Related Articles

Improve Article

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

  • Last Updated : 14 Jul, 2021

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

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 substree
        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);
}
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 substree
        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;
}
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 substree
        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);
}
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 Node: 6
Node: 0, Parent Node: 5
Node: 9, Parent Node: 6

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

Attention reader! Don’t stop learning now. Get hold of all the important DSA concepts with the DSA Self Paced Course at a student-friendly price and become industry ready.  To complete your preparation from learning a language to DS Algo and many more,  please refer Complete Interview Preparation Course.

In case you wish to attend live classes with experts, please refer DSA Live Classes for Working Professionals and Competitive Programming Live for Students.




My Personal Notes arrow_drop_up
Recommended Articles
Page :