An AVL Tree (Adelson-Velsky and Landis Tree) is a self-balancing binary search tree. The difference between an AVL tree and a regular binary search tree is that an AVL tree maintains a balance factor of each node, which ensures that the tree remains balanced. This helps ensure that the height of the tree remains logarithmic, ensuring faster search, insertion, and deletion operations.
An AVL Tree is a type of binary search tree where the difference in heights between the left and right subtrees (called the balance factor) is at most 1 for all nodes. If the balance factor exceeds this limit, rebalancing operations like rotations are performed to restore balance.
#include <stdio.h> #include <stdlib.h> struct Node { int data; struct Node* left; struct Node* right; int height; }; // Function to get the height of the node int height(struct Node* node) { if (node == NULL) return 0; return node->height; } // Function to get the balance factor of the node int balanceFactor(struct Node* node) { if (node == NULL) return 0; return height(node->left) - height(node->right); } // Function to create a new node struct Node* newNode(int data) { struct Node* node = (struct Node*)malloc(sizeof(struct Node)); node->data = data; node->left = NULL; node->right = NULL; node->height = 1; return node; } int main() { struct Node* root = newNode(10); root->left = newNode(5); root->right = newNode(15); printf("Root Node: %d\\n", root->data); printf("Balance Factor of Root: %d\\n", balanceFactor(root)); return 0; }
Root Node: 10 Balance Factor of Root: 0
AVL Trees involve several key operations like insertion, deletion, and balancing through rotations. Here are the types of rotations that help maintain balance:
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 the new root return x; }
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 the new root return y; }
During insertion, after adding a node, we check the balance factor of each ancestor node, and if any node has an imbalance, we perform rotations to restore balance.
struct Node* insert(struct Node* node, int data) { // 1. Perform normal BST insertion if (node == NULL) return newNode(data); if (data < node->data) node->left = insert(node->left, data); else if (data > node->data) node->right = insert(node->right, data); else return node; // Duplicates not allowed // 2. Update height of this ancestor node node->height = 1 + max(height(node->left), height(node->right)); // 3. Get the balance factor int balance = balanceFactor(node); // 4. If this node becomes unbalanced, then there are 4 cases // Left Left Case if (balance > 1 && data < node->left->data) return rightRotate(node); // Right Right Case if (balance < -1 && data > node->right->data) return leftRotate(node); // Left Right Case if (balance > 1 && data > node->left->data) { node->left = leftRotate(node->left); return rightRotate(node); } // Right Left Case if (balance < -1 && data < node->right->data) { node->right = rightRotate(node->right); return leftRotate(node); } return node; // Return the (unchanged) node pointer }
int main() { struct Node* root = NULL; root = insert(root, 10); root = insert(root, 20); root = insert(root, 30); // Causes imbalance and rotation printf("Root Node: %d\\n", root->data); return 0; }
Similar to insertion, after deleting a node, we check for imbalance and perform necessary rotations to restore balance.
Help others discover Technorank Learning by sharing your honest experience.
Your support inspires us to keep building!