Table of contents
1.
Introduction
1.1.
Problem Statement 🧾
1.2.
Sample Examples🧐
2.
Approach #1🧑‍💻
2.1.
Pseudocode
2.2.
Implementation in C++ 🧑‍💻
2.2.1.
Time Complexity ⌛
2.2.2.
Space Complexity 🚀
3.
Approach #2🧑‍💻
3.1.
Pseudocode
3.2.
Implementation in C++ 🧑‍💻
3.2.1.
Time Complexity ⌛
3.2.2.
Space Complexity 🚀
4.
Frequently Asked Questions 
4.1.
What are AVL trees?
4.2.
What is a binary tree?
4.3.
What exactly is a perfect binary tree?
5.
Conclusion 
Last Updated: Mar 27, 2024
Medium

Convert a normal BST to a Balanced BST

Author Harsh
0 upvote
Career growth poll
Do you think IIT Guwahati certified course can help you in your career?

Introduction

A tree in which every node can have at max 2 children is known as a binary tree and a BST is a variation of a binary tree in which all of the nodes present in the left subtree are smaller than the root node and all of the nodes present in the right side of the root node are greater than the root node. 

Normal BST to Balanced BST

In this article, we will discuss a coding problem in which we have to convert a normal BST to a balanced BST.

Problem Statement 🧾

Ninja has given you a BST. Your task is to convert a normal BST to a balanced BST.

A binary search tree is balanced when the difference between the height of the left child and the height of the right child is not more than 1 and this property holds for every node present in the BST. For example,

difference b/q normal and balanced BST

Sample Examples🧐

Input

input

 

Output

output

 

Explanation

As we can see in the below image the height difference between the left and the right child for some nodes is more than 1 in our original BST but after converting the height difference becomes 0 or 1 for all of the nodes present in the BST.

Explaination

Approach #1🧑‍💻

The very basic approach would be to traverse the given tree in inorder and while traversing keep on inserting the nodes into a self-balancing tree like an AVL tree or red-black tree.

In this article, we will be using AVL tree. To know more about insertion in AVL tree have a look at the below-mentioned blog.

Pseudocode

  1. Start
     
  2. Store the inorder traversal of our tree into an Array.
     
  3. Traverse the array and keep on inserting the values one-by-one into a self-balancing AVL tree.
     
  4. Exit
     

In the below implementation most of the code has been taken from this “Insertion in AVL Trees” article. To fully understand the code make sure you go through the above article first.

Implementation in C++ 🧑‍💻

#include <bits/stdc++.h>

// AVL Tree implementation
// To know more about it. Have a look at the article mentioned above.
#include "AVL_Tree.h"

using namespace std;

// Node
class Node
{
public:
    int data;
    Node *left, *right;
    Node(int val)
    {
        data = val;
        left = right = nullptr;
    }
};

// generate an array from inorder traversal
void genArray(Node *root, vector<Node *> &arr)
{
    if (root == nullptr)
        return;

    genArray(root->left, arr);
    arr.push_back(root);
    genArray(root->right, arr);
}

// preorder traversal
void preorder(Node *root)
{
    if (root == nullptr)
        return;

    cout << root->data << " ";
    preorder(root->left);
    preorder(root->right);
}

// preorder traversal for AVL tree
void preOrderAVL(AVLtree *root)
{
    if (root != NULL)
    {
        cout << root->data << " ";
        preOrderAVL(root->left);
        preOrderAVL(root->right);
    }
}

int main()
{

    /*
            Creating BST
                 20
               /   \
             10    40
               \
               12
               /
             11
    */
    Node *root = nullptr;
    root = new Node(20);
    root->left = new Node(10);
    root->right = new Node(40);
    root->left->right = new Node(12);
    root->left->right->left = new Node(11);

    cout << "Before Converting: ";
    preorder(root);

    // generating array from inorder traversal
    vector<Node *> arr;
    genArray(root, arr);

    // traversing the array and inserting the values into
    // self-balancing AVL tree one-by-one
    AVLtree *tree = nullptr;
    for (int i = 0; i < arr.size(); i++)
    {
        tree = insertNode(tree, arr[i]->data);
    }

    cout << "\n";
    cout << "After converting: ";
    preOrderAVL(tree);
    cout << "\n";

    return 0;
}
You can also try this code with Online C++ Compiler
Run Code


Output

Before Converting: 20 10 12 11 40 
After converting: 11 10 20 12 40  


Time Complexity ⌛

Insertion in AVL trees requires the same amount of time as a BST, which is O(h), where h is the tree's height. However, because our tree is equally balanced in height, the height is always O (log n). Considering all of these elements, the insert function's time complexity is determined to be O. (log n).

Thus, the overall time complexity (average and worst) of the insertion function in an AVL tree is  O(log n).

The time required to generate the sorted array is O(N), as we are only doing the in-order traversal. Where N is the total number of nodes in our BST.

We are inserting N nodes into the AVL tree so the overall time complexity of our program is O(Nlog n).
 

Space Complexity 🚀

We are generating a new Array to store the nodes. So, the space complexity of our program would be O(N). Where N is the number of nodes in our BST. 

Approach #2🧑‍💻

We can construct a balanced BST using the following technique. We can do an inorder traversal storing the result into an array. Then we can use this array to build a Balanced BST.

As the result of the inorder traversal of BST is sorted so our array would be sorted. So, we can find the mid element of the array and make it the root node of our BST and can repeat the same process for the left and right subarray.

Pseudocode

ALGO_CONVERT (ARR, START, END):
    If START > END:
        Return NULL;

    mid <- (START + END) / 2;
    NODE root <- ARR[mid]

    root->left = ALGO_CONVERT(ARR, START, mid-1);
    root->right = ALGO_CONVERT(ARR, mid+1, END);

    return root

Implementation in C++ 🧑‍💻

#include <bits/stdc++.h>

using namespace std;

// Node
class Node {
public:
    int data;
    Node *left, *right;
    Node(int val) {
        data = val;
        left = right = nullptr;
    }
};

// function to convert BST to balanced BST
Node* convert(vector<Node* > &arr, int start, int end) {
    
    // base case
    if (start > end) return nullptr;
 
    // finding the mid element of our sorted array
    int mid = (start + end)/2;
    Node *root = arr[mid];
 
    /* constructing left and right subtress using the index */
    root->left  = convert(arr, start, mid-1);
    root->right = convert(arr, mid+1, end);
 
    return root;
}

// generated array from inorder traversal
void genArray(Node* root, vector<Node*> &arr){
    if (root == nullptr) return;

    genArray(root->left, arr);
    arr.push_back(root);
    genArray(root->right, arr);
}

// preorder traversal
void preorder(Node* root){
    if (root == nullptr) return;

    cout << root->data << " ";
    preorder(root->left);
    preorder(root->right);
}

int main() {

    /*
            Creating BST
                 20
               /   \
             10    40
               \
               12
               /
             11
    */
    Node *root = nullptr;
    root = new Node(20);
    root->left = new Node(10);
    root->right = new Node(40);
    root->left->right = new Node(12);
    root->left->right->left = new Node(11);

    cout << "Before Converting: ";
    preorder(root);

    // generating array from inorder traversal
    vector<Node*> arr;
    genArray(root, arr);

    // converting to balanced BST
    root = convert(arr, 0, arr.size() - 1);

    cout << "\n";
    cout << "After converting: ";
    preorder(root);
    cout << "\n";
    
    return 0;
}
You can also try this code with Online C++ Compiler
Run Code

 

Output

Before Converting: 20 10 12 11 40 
After converting: 12 10 11 20 40 

 

Time Complexity ⌛

The time required to generate the sorted array is O(N),  as we are only doing the in-order traversal. After generating we are traversing the sorted array only once by finding the mid element and going to the left or right subarray recursively this step takes O(N) time as well. So, the overall time complexity of our program is O(N). where N is the number of nodes in our BST.
 

Space Complexity 🚀

We are generating a new Array to store the nodes. So, the space complexity of our program would be O(N). Where N is the number of nodes in our BST.

Check out this problem - Longest Subarray With Sum K 

Frequently Asked Questions 

What are AVL trees?

Adelson-Velskii and Landis trees, or AVL trees, are binary search trees with height-balanced nodes. We can insert and delete at any node as long as we reorganize the tree if the insertion or deletion causes an imbalance.
 

What is a binary tree?

A binary tree is a tree data structure having a maximum of two children. There can only be two children per element in a binary tree, hence we usually refer to them as the left and right children.
 

What exactly is a perfect binary tree?

A perfect binary tree is a tree in which every node has two children or no children at all.
 

Conclusion 

In this article, we have extensively discussed a coding problem in which we have to convert a normal BST to a Balanced BST. We have seen a simple yet optimal solution to solve the problem.
 

If you think this blog has helped you enhance your knowledge about the above question, and if you would like to learn more, check out our articles 

and many more on our website.

Visit our website to read more such blogs. Make sure that you enroll in the courses provided by us, take mock tests and solve problems and interview puzzles available. Also, you can pay attention to interview stuff- interview experiences and an interview bundle for placement preparations.

Please upvote our blog to help other ninjas grow.

Happy Learning!

Live masterclass