How to insert a node in an AVL tree

AVL trees

AVL trees are self-balancing binary search trees. This means that whenever an imbalanceAn imbalance in a binary search tree happens due to one subtree of a node being heavier than the other subtree. is created via the insertion or deletion of a node(s), these trees can restore the balance.

Note: To learn more about AVL trees and the different types of imbalances that can arise in them due to the insertion/deletion of a node(s), refer to this link.

This maintenance of balance in an AVL tree allows operations such as insertion, deletion, and searching to run in O(log(N))O(log(N)) time. Thus, it makes them much more efficient than simple binary search trees, which take O(N)O(N) time in the worst case.

Insertions

Efficiently inserting a new node in an AVL tree requires a recursive approach that involves 2 main steps:

  1. Inserting the node itself: We insert a node into the tree the same way it would be inserted into a binary search tree—recursively. This new node will become a leaf node.

  2. Rebalancing the tree once the node is inserted: This happens once the backtracking starts. Starting from the newly inserted node (currently a leaf node), we travel up the tree until the first unbalanced node (with a balance factorThe balance factor of a node is the difference in the height of the left and right sub-tree. The balance factor of every node in the AVL tree should be either +1, 0 or -1. that lies outside the range [-1, 1]) is found. Next, we perform the required rotationsRotations involve switching around positions of nodes in the unbalanced node's sub-tree(s) each time the balance factor is disrupted. on the subtree of this unbalanced node to rebalance it. This is repeated until we reach the root node of the tree and the recursion backtracking ends.

Insert the node itself

To insert a node in a BST, we first compare the value of xx (the node being inserted) with the value of the root node. If this value is less than the root node's value, we go to the left child, making it the root node for the next recursive call. Similarly, if this value is greater than the root node's value. We go to the right child and make it the root node for the next recursive call. We keep making these recursive calls until we reach a leaf node. If the value of xx is less than this leaf node's value, we make it the left child of this leaf node. Similarly, if the value of xx is greater than this leaf node's value, we make it the right child of this leaf node.

The example below demonstrates this (the current root node during the recursive calls is colored orange):

1 of 13

Once the node is inserted into the tree, the backtracking can begin since the base case is reached for the first time.

Rebalance the tree once the node is inserted

During backtracking, we check the balance factor of each node. If the balance factor is in the range [-1, 1], we do nothing and allow backtracking to proceed as it is. However, if the node is unbalanced, we need to perform rotation(s) on it to rebalance it.

Note: To learn more about how the rebalancing of an AVL tree is done using rotations, refer to this link.

If the balance factor is 2, then this means that the unbalanced node's left subtree is heavier than the right one. Thus, there is either a left-left imbalance or a left-right imbalance. Now, if the balance factor of the unbalanced node's left child is greater than or equal to 1 (or, alternatively, if the value of xx is less than the value of the unbalanced node's left child), this narrows it down to a left-left imbalance and a right rotation needs to be applied on the unbalanced node, otherwise, the imbalance is a left-right one and a left-right rotation needs to be applied.

Similarly, if the balance factor is -2, then this means that the unbalanced node's right subtree is heavier than the left one. Thus, there is either a right-right imbalance or a right-left imbalance. Now, if the balance factor of the unbalanced node's right child is less than or equal to 0 (or, alternatively, if the value of xx is greater than the value of the unbalanced node's right child), this narrows it down to a right-right imbalance and a left rotation needs to be applied on the unbalanced node. Otherwise, the imbalance is a right-left one and a right-left rotation needs to be applied.

This backtracking process is depicted below, continuing the same example from above (the current root node during each step of the backtracking is colored red):

1 of 18

Once the backtracking ends, we have successfully inserted new_node . Another example is demonstrated below:

1 of 22

Code example

The insertNode() function, highlighted in the lines below, implements the steps discussed above for inserting a node in an AVL tree:

#include <iostream>
using namespace std;
class Node
{
public:
int value;
Node * left_child;
Node * right_child;
Node()
{
value = 0;
left_child = NULL;
right_child = NULL;
}
Node(int v)
{
value = v;
left_child = NULL;
right_child = NULL;
}
};
class AVLtree
{
public:
Node * root;
AVLtree()
{
root = NULL;
}
int height(Node * r)
{
if (r == NULL)
{
return -1;
}
else
{
int left_subtree_height = height(r->left_child);
int right_subtree_height = height(r->right_child);
if (left_subtree_height > right_subtree_height)
{
return (left_subtree_height + 1);
}
else
{
return (right_subtree_height + 1);
}
}
}
int getBalanceFactor(Node * n)
{
if (n == NULL)
{
return -1;
}
return height(n->left_child) - height(n->right_child);
}
Node * rightRotate(Node * x)
{
Node * y = x->left_child;
Node * T2 = y->right_child;
// Perform rotation
y->right_child = x;
x->left_child = T2;
return y;
}
Node * leftRotate(Node * x)
{
Node * y = x->right_child;
Node * T2 = y->left_child;
// Perform rotation
y->left_child = x;
x->right_child = T2;
return y;
}
Node * balanceTree(int balance_factor, Node * unbalanced_node)
{
if (balance_factor > 1)
{
// left-left imbalance
if(getBalanceFactor(unbalanced_node->left_child) >= 0)
{
unbalanced_node = rightRotate(unbalanced_node);
return unbalanced_node;
}
// left-right imbalance
else if(getBalanceFactor(unbalanced_node->left_child) == -1)
{
unbalanced_node->left_child = leftRotate(unbalanced_node->left_child);
unbalanced_node = rightRotate(unbalanced_node);
return unbalanced_node;
}
}
if (balance_factor < -1)
{
// right-right imbalance
if(getBalanceFactor(unbalanced_node->right_child) <= -0)
{
unbalanced_node = leftRotate(unbalanced_node);
return unbalanced_node;
}
// right-left imbalance
else if(getBalanceFactor(unbalanced_node->right_child) == 1)
{
unbalanced_node->right_child = rightRotate(unbalanced_node->right_child);
unbalanced_node = leftRotate(unbalanced_node);
return unbalanced_node;
}
}
}
Node * insertNode(Node * root, Node * new_node)
{
// inserting the node
if (root == NULL)
{
root = new_node;
return root;
}
if (new_node->value < root->value)
{
root->left_child = insertNode(root->left_child, new_node);
}
else if (new_node->value > root->value)
{
root->right_child = insertNode(root->right_child, new_node);
}
// node has been inserted
// checking if node needs to be rebalanced
int bf = getBalanceFactor(root);
if(bf!=-1 && bf!=0 && bf!=1) // if true, then node needs to be rebalanced
{
root = balanceTree(bf, root);
}
return root; // backtrack
}
};
void prettyPrintTree(Node * r, int space)
{
if (r == NULL)
{
return;
}
space += 10;
prettyPrintTree(r->right_child, space);
cout << endl;
for (int i = 10; i < space; i++)
{
cout << " ";
}
cout << r->value << "\n";
prettyPrintTree(r->left_child, space);
}
int main()
{
AVLtree obj;
Node * n1 = new Node(30);
Node * n2 = new Node(10);
Node * n3 = new Node(50);
Node * n4 = new Node(8);
Node * n5 = new Node(18);
Node * n6 = new Node(58);
Node * n7 = new Node(5);
Node * n8 = new Node(6);
obj.root = obj.insertNode(obj.root, n1);
obj.root = obj.insertNode(obj.root, n2);
obj.root = obj.insertNode(obj.root, n3);
obj.root = obj.insertNode(obj.root, n4);
obj.root = obj.insertNode(obj.root, n5);
obj.root = obj.insertNode(obj.root, n6);
obj.root = obj.insertNode(obj.root, n7);
obj.root = obj.insertNode(obj.root, n8);
prettyPrintTree(obj.root, 1);
return 0 ;
}

Explanation

In the output of the code above, the nodes of the tree have been printed in a 2-D manner to help with visualization. To keep the implementation of the prettyPrintTree() function straightforward, the tree is rotated 90o to the left in the output.

Free Resources

Copyright ©2025 Educative, Inc. All rights reserved