A Balanced Binary Tree, also known as a height-balanced binary tree, is a binary tree in which the height of every node’s left and right subtrees differs by at most one. This balance condition ensures that the tree maintains a logarithmic height, which in turn guarantees O(log n) time complexity for operations such as insertion, deletion, and search.
In this article, we will learn how to implement a Balanced Binary Tree in C++ and its basic operations.
A Balanced Binary Tree is a binary tree where the heights of the left and right subtrees of any node differ by at most one. This balance condition is maintained through rotations during insertions and deletions.
Properties of Balanced Binary Trees- The height difference between the left and right subtrees of any node is at most 1.
- Both the left and right subtrees are also balanced binary trees.
- The height of an empty tree is considered -1.
- The height of a tree with one node is 0.
 Balanced vs Unbalanced Binary Tree Implementation of Balanced Binary Tree in C++ LanguageA Balanced Binary Tree can be implemented using a self-balancing binary search tree, such as an AVL tree or a Red-Black tree. For this implementation, we’ll use an AVL tree, which maintains balance by storing height information in each node and performing rotations when necessary.
Representation of Balanced Binary Tree in C++To represent a balanced binary tree we will implement a class Node that will represent a single node of the balanced binary tree and BalancedBinaryTree class that will contain all the required member functions. We will use template to keep the balanced binary tree generic so that it can support multiple data types.
template <typename T> class Node { public: T data; Node* left; Node* right; int height; }; Here,
- data: stores the value in the node.
- left and right: store pointers to the left and right child nodes.
- height: stores the height of the subtree rooted at this node.
The following diagram represents the structure of a balanced binary tree:
 Balanced Binary Tree Basic Operations of Balanced Binary Tree in C++Following are some of the basic operations of a Balanced Binary Tree that are required to manipulate its elements:
Operation
| Description
| Time Complexity
| Space Complexity
|
---|
Insert
| Inserts a new element into the tree
| O(log n)
| O(1)
|
---|
Delete
| Removes an element from the tree
| O(log n)
| O(1)
|
---|
Search
| Searches for an element in the tree
| O(log n)
| O(1)
|
---|
Height
| Calculates the height of a node
| O(1)
| O(1)
|
---|
Balance Factor
| Calculates the balance factor of a node
| O(1)
| O(1)
|
---|
Rotate Right
| Performs a right rotation on a node
| O(1)
| O(1)
|
---|
Rotate Left
| Performs a left rotation on a node
| O(1)
| O(1)
|
---|
Here, n represents the number of nodes in the tree.
Implementation of Insert Function- Perform a standard BST insertion.
- Update the height of the ancestors nodes.
- Check the balance factor of the ancestors.
- If the node becomes unbalanced, perform one of the four rotations:
- Left-Left Case: Right Rotation
- Left-Right Case: Left Rotation followed by Right Rotation
- Right-Right Case: Left Rotation
- Right-Left Case: Right Rotation followed by Left Rotation
Implementation of Delete Function- Perform a standard BST deletion.
- Update the height of the ancestors nodes.
- Check the balance factor of the ancestors.
- If the node becomes unbalanced, perform one of the four rotations as in insertion.
Implementation of Height and Balance Factor Functions- Height: Return the height stored in the node, or 0 if the node is null.
- Balance Factor: Calculate the difference between the heights of left and right subtrees and return the calculated value.
Implementation of Rotation Functions- Right Rotation:
- Make the left child of the current node the new root of the subtree.
- Make the old root the right child of the new root.
- Update the heights of the nodes.
- Left Rotation:
- Make the right child of the current node the new root of the subtree.
- Make the old root the left child of the new root.
- Update the heights of the nodes.
C++ Program to Implement Balanced Binary TreeThe following program demonstrates the implementation of a Balanced Binary Tree in C++.
C++
// C++ Program to Implement Balanced Binary Tree
#include <algorithm>
#include <iostream>
using namespace std;
template <typename T> class BalancedBinaryTree {
private:
// Node structure definition
struct Node {
T data;
Node* left;
Node* right;
int height;
Node(T value)
: data(value)
, left(nullptr)
, right(nullptr)
, height(1)
{
}
};
Node* root;
// Function to get the height of the node
int height(Node* node)
{
return node ? node->height : 0;
}
// Function to get the balance factor of the node
int balanceFactor(Node* node)
{
return node ? height(node->left)
- height(node->right)
: 0;
}
// Function to update the height of the node
void updateHeight(Node* node)
{
node->height = 1
+ max(height(node->left),
height(node->right));
}
// Right rotation function
Node* rotateRight(Node* y)
{
Node* x = y->left;
Node* T2 = x->right;
x->right = y;
y->left = T2;
updateHeight(y);
updateHeight(x);
return x;
}
// Left rotation function
Node* rotateLeft(Node* x)
{
Node* y = x->right;
Node* T2 = y->left;
y->left = x;
x->right = T2;
updateHeight(x);
updateHeight(y);
return y;
}
// Function to insert a node
Node* insert(Node* node, T key)
{
// Perform the normal BST insertion
if (!node)
return new Node(key);
if (key < node->data)
node->left = insert(node->left, key);
else if (key > node->data)
node->right = insert(node->right, key);
else
return node; // Duplicate keys are not allowed
// Update height of this ancestor node
updateHeight(node);
// Get the balance factor to check whether this node
// became unbalanced
int balance = balanceFactor(node);
// If the node becomes unbalanced, there are 4 cases
// Left Left Case
if (balance > 1 && key < node->left->data)
return rotateRight(node);
// Right Right Case
if (balance < -1 && key > node->right->data)
return rotateLeft(node);
// Left Right Case
if (balance > 1 && key > node->left->data) {
node->left = rotateLeft(node->left);
return rotateRight(node);
}
// Right Left Case
if (balance < -1 && key < node->right->data) {
node->right = rotateRight(node->right);
return rotateLeft(node);
}
return node;
}
// Function to find the node with the minimum value
// (used in deletion)
Node* findMin(Node* node)
{
while (node->left)
node = node->left;
return node;
}
// Function to delete a node
Node* remove(Node* node, T key)
{
// Perform standard BST delete
if (!node)
return nullptr;
if (key < node->data)
node->left = remove(node->left, key);
else if (key > node->data)
node->right = remove(node->right, key);
else {
if (!node->left || !node->right) {
Node* temp
= node->left ? node->left : node->right;
if (!temp) {
temp = node;
node = nullptr;
}
else
*node = *temp;
delete temp;
}
else {
Node* temp = findMin(node->right);
node->data = temp->data;
node->right
= remove(node->right, temp->data);
}
}
if (!node)
return nullptr;
// Update height of the current node
updateHeight(node);
// Get the balance factor
int balance = balanceFactor(node);
// Balance the node if it has become unbalanced
// Left Left Case
if (balance > 1 && balanceFactor(node->left) >= 0)
return rotateRight(node);
// Left Right Case
if (balance > 1 && balanceFactor(node->left) < 0) {
node->left = rotateLeft(node->left);
return rotateRight(node);
}
// Right Right Case
if (balance < -1 && balanceFactor(node->right) <= 0)
return rotateLeft(node);
// Right Left Case
if (balance < -1
&& balanceFactor(node->right) > 0) {
node->right = rotateRight(node->right);
return rotateLeft(node);
}
return node;
}
// Function to search for a key in the tree
bool search(Node* node, T key)
{
if (!node)
return false;
if (node->data == key)
return true;
if (key < node->data)
return search(node->left, key);
return search(node->right, key);
}
// Function for inorder traversal of the tree
void inorderTraversal(Node* node)
{
if (node) {
inorderTraversal(node->left);
cout << node->data << " ";
inorderTraversal(node->right);
}
}
public:
// Constructor
BalancedBinaryTree()
: root(nullptr)
{
}
// Public insert function
void insert(T key) { root = insert(root, key); }
// Public remove function
void remove(T key) { root = remove(root, key); }
// Public search function
bool search(T key) { return search(root, key); }
// Public function to print the inorder traversal
void printInorder()
{
inorderTraversal(root);
cout << endl;
}
};
int main()
{
BalancedBinaryTree<int> tree;
// Insert elements
tree.insert(10);
tree.insert(20);
tree.insert(30);
tree.insert(40);
tree.insert(50);
tree.insert(25);
cout << "Inorder traversal of the constructed Balanced "
"Binary Tree"
<< endl;
tree.printInorder();
// Search for a key
int searchKey = 30;
cout << "Searching for key " << searchKey << ": "
<< (tree.search(searchKey) ? "Found" : "Not Found")
<< endl;
// Remove a key
int removeKey = 20;
tree.remove(removeKey);
cout << "Inorder traversal after removing " << removeKey
<< ": ";
tree.printInorder();
return 0;
}
OutputInorder traversal of the constructed Balanced Binary Tree
10 20 25 30 40 50
Searching for key 30: Found
Inorder traversal after removing 20: 10 25 30 40 50
Applications of Balanced Binary TreesFollowing are some of the common applications of balanced binary trees:
- Many database systems use balanced trees (like B-trees, which are a generalization of balanced binary trees) for efficient indexing.
- Some file systems use balanced trees to organize directory structures.
- Some memory allocators use balanced trees to keep track of free memory blocks.
- Balanced binary trees can be used to represent and evaluate arithmetic expressions.
- Balanced trees can be used to implement efficient lookup tables for network routing.
|