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

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;}
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)
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 nodestruct 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 heightsvoid 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 Casestruct 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 Casestruct 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 Casestruct AVLwithparent* LRR(    struct AVLwithparent* root){    root->left = RRR(root->left);    return LLR(root);}  // Function to handle right left casestruct AVLwithparent* RLR(    struct AVLwithparent* root){    root->right = LLR(root->right);    return RRR(root);}  // Function to insert a node in// the AVL treestruct 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 treevoid 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 Codeint 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);}
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 nodestruct 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 heightsvoid 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 Casestruct 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 Casestruct 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 Casestruct AVLwithparent* LRR(    struct AVLwithparent* root){    root->left = RRR(root->left);    return LLR(root);}  // Function to handle right left casestruct AVLwithparent* RLR(    struct AVLwithparent* root){    root->right = LLR(root->right);    return RRR(root);}  // Function to insert a node in// the AVL treestruct 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 treebool 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 Codeint 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;}
value found

Time Complexity: O(log N), where N is the number of nodes of the treeAuxiliary 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)
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 nodestruct AVLwithparent {    struct AVLwithparent* left;    struct AVLwithparent* right;    int key;    struct AVLwithparent* par;    int height;};  // Function to print the preorder// traversal of the AVL treevoid 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 heightsvoid 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 Casestruct 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 Casestruct 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 Casestruct AVLwithparent* LRR(    struct AVLwithparent* root){    root->left = RRR(root->left);    return LLR(root);}  // Function to handle right left casestruct AVLwithparent* RLR(    struct AVLwithparent* root){    root->right = LLR(root->right);    return RRR(root);}  // Function to balance the tree after// deletion of a nodestruct 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 treestruct 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 treestruct 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 Codeint 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);}
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 treeAuxiliary Space: O(1)
AVL-Tree
Balanced Binary Search Trees
Picked
Self-Balancing-BST
Data Structures
Tree
Data Structures
Tree
AVL-Tree
Writing code in comment?
Please use ide.geeksforgeeks.org,
generate link and share the link here.
Introduction to Tree Data Structure
Program to implement Singly Linked List in C++ using class
Hash Functions and list/types of Hash functions
Insertion in a B+ tree
TCS NQT Coding Sheet
Tree Traversals (Inorder, Preorder and Postorder)
Binary Tree | Set 1 (Introduction)
Level Order Binary Tree Traversal
AVL Tree | Set 1 (Insertion)
Inorder Tree Traversal without Recursion