Height Balanced Binary Tree in c++

 

A height balanced binary tree, also known as an AVL tree, is a type of binary search tree that is designed to maintain a balance between the left and right subtrees. This balance is achieved by ensuring that the height difference between the left and right subtrees is not greater than 1. In this article, we will discuss the concept of height balanced binary trees and how to implement them in C++.

A binary search tree is a type of binary tree where the left subtree of a node contains only nodes with keys that are less than the node's key, and the right subtree of a node contains only nodes with keys that are greater than the node's key. This allows for efficient searching, insertion, and deletion operations. However, if the tree becomes unbalanced, the performance of these operations can degrade.

An AVL tree is a type of binary search tree that maintains balance by ensuring that the height difference between the left and right subtrees is not greater than 1. This is achieved through a process called rotation. Rotation is the process of moving a node and its subtrees to a different position in the tree. There are two types of rotations: left rotation and right rotation. A left rotation is performed when the right subtree of a node is taller than its left subtree. A right rotation is performed when the left subtree of a node is taller than its right subtree.

In order to implement an AVL tree in C++, we first need to define the structure of a node. The node structure should contain the key, the left and right pointers, and the height of the node. The height of the node is used to determine the balance of the tree.

struct Node { int key; struct Node *left; struct Node *right; int height; };

The next step is to implement the insertion operation. The insertion operation is similar to the insertion operation in a binary search tree. However, after inserting a new node, we need to check the balance of the tree and perform rotations if necessary.

// Insert a new node into the AVL tree struct Node* insert(struct Node* node, int key) { // Perform the standard BST insertion if (node == NULL) return(newNode(key));

if (key < node->key) node->left = insert(node->left, key);
 else if (key > node->key) 
 node->right = insert(node->right, key);
 else 
// Equal keys are not allowed in BST 
 return node;  
// Update the height of the current node 
 node->height = 1 + max(height(node->left), height(node->right));
 // Get the balance factor of this node to check whether // this node became unbalanced 
 int balance = getBalance(node); 
 // If this node becomes unbalanced, then there are 4 cases // Left Left Case if (balance > 1 && key < node->left->key) return rightRotate(node);  
// Right Right Case 
if (balance < -1 && key > node->right->key) return leftRotate(node); 
 // Left Right Case 
 if (balance > 1 && key > node->left->key) { node->left = leftRotate(node->left); return rightRotate(node); 
 // Right Left Case if (balance < -1 && key < node->right->key
 node->right = rightRotate(node->right); return leftRotate(node); }


// Return the (unchanged) node pointer return node;

}

The next step is to implement the rotations. The leftRotate and rightRotate functions are used to perform the rotations. The leftRotate function is used when the right subtree of a node is taller than its left subtree, and the rightRotate function is used when the left subtree of a node is taller than its right subtree.

// A utility function to left rotate subtree rooted with x // See the diagram given above. struct Node *leftRotate(struct Node *x) { struct Node *y = x->right; struct Node *T2 = y->left;

// Perform rotation 
y->left = x; x->right = T2;
 // Update heights 
 x->height = max(height(x->left), height(x->right))+1;
 y->height = max(height(y->left), height(y->right))+1;
 // Return new root
  return y; 
 

}

// A utility function to right rotate subtree rooted with y // See the diagram given above. struct Node *rightRotate(struct Node *y) { struct Node *x = y->left; struct Node *T2 = x->right;

// Perform rotation 
 x->right = y; y->left = T2;
 // Update heights 
 y->height = max(height(y->left), height(y->right))+1
x->height = max(height(x->left), height(x->right))+1;
 // Return new root 
return x;

}

The final step is to implement the deletion operation. The deletion operation is similar to the deletion operation in a binary search tree. However, after deleting a node, we need to check the balance of the tree and perform rotations if necessary.

// A utility function to delete the node with the given key // from the AVL tree struct Node* deleteNode(struct Node* root, int key) { // Step 1 - Perform standard BST delete if (root == NULL) return root;

// If the key to be deleted is smaller than the // root's key, then it lies in left subtree 
if ( key < root->key ) root->left = deleteNode(root->left, key); 
 // If the key to be deleted is greater than the // root's key, then it lies in right subtree 
else if( key > root->key ) root->right = deleteNode(root->right, key);
 // if key is same as root's key, then this is the node // to be deleted 
 else
 // node with only one child or no child 
 if( (root->left == NULL) || (root->right == NULL) ) {
 struct Node *temp = root->left ? root->left : root->right;
 // No child case 
 if (temp == NULL) { temp = root; root = NULL; }
 else 
// One child case
  *root = *temp;
 // Copy the contents of // the non-

null child free(temp); } else { // node with two children: Get the inorder // successor (smallest in the right subtree) struct Node* temp = minValueNode(root->right);

// Copy the inorder successor's data to this node
  root->key = temp->key;
 // Delete the inorder successor 
 root->right = deleteNode(root->right, temp->key); 
 } } 
 // If the tree had only one node then return 
 if (root == NULL) return root;
 // Step 2 - Update the height of the current node
  root->height = 1 + max(height(root->left), height(root->right));
 // Step 3 - Get the balance factor of this node (to check whether // this node became unbalanced)
  int balance = getBalance(root); 
 // If this node becomes unbalanced, then there are 4 cases // Left Left Case if (balance > 1 && getBalance(root->left) >= 0) return rightRotate(root); 
 // Left Right Case 
if (balance > 1 && getBalance(root->left) < 0) { root->left = leftRotate(root->left); return rightRotate(root);
 }  
// Right Right Case 
if (balance < -1 && getBalance(root->right) <= 0) return leftRotate(root);
 // Right Left Case
  if (balance < -1 && getBalance(root->right) > 0) { 
root->right = rightRotate(root->right);
 return leftRotate(root);
 } 
 return root;

}

In conclusion, an AVL tree is a type of binary search tree that maintains balance by ensuring that the height difference between the left and right subtrees is not greater than 1. It is implemented in C++ by defining the structure of a node, implementing the insertion, deletion and rotation operations, and checking the balance of the tree after each operation. By using an AVL tree, we can ensure that the performance of searching, inserting, and deleting operations remains optimal even when the tree becomes large.

Height Balanced Binary Tree in c++