-
Notifications
You must be signed in to change notification settings - Fork 289
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
3464663
commit a571bfc
Showing
6 changed files
with
790 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,215 @@ | ||
#include <stdio.h> | ||
#include <stdlib.h> | ||
|
||
// AVL Tree | ||
struct Node { | ||
int data; | ||
struct Node* left; | ||
struct Node* right; | ||
int height; | ||
}; | ||
|
||
|
||
int height(struct Node* node) { | ||
if (node == NULL) | ||
return 0; | ||
return node->height; | ||
} | ||
|
||
|
||
int max(int a, int b) { | ||
return (a > b) ? a : b; | ||
} | ||
|
||
|
||
struct Node* createNode(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; | ||
} | ||
|
||
|
||
struct Node* rightRotate(struct Node* y) { | ||
struct Node* x = y->left; | ||
struct Node* T2 = x->right; | ||
|
||
x->right = y; | ||
y->left = T2; | ||
|
||
y->height = max(height(y->left), height(y->right)) + 1; | ||
x->height = max(height(x->left), height(x->right)) + 1; | ||
|
||
return x; | ||
} | ||
|
||
struct Node* leftRotate(struct Node* x) { | ||
struct Node* y = x->right; | ||
struct Node* T2 = y->left; | ||
|
||
|
||
y->left = x; | ||
x->right = T2; | ||
|
||
|
||
x->height = max(height(x->left), height(x->right)) + 1; | ||
y->height = max(height(y->left), height(y->right)) + 1; | ||
|
||
return y; | ||
} | ||
|
||
int getBalance(struct Node* node) { | ||
if (node == NULL) | ||
return 0; | ||
return height(node->left) - height(node->right); | ||
} | ||
|
||
struct Node* insertNode(struct Node* node, int data) { | ||
|
||
if (node == NULL) | ||
return createNode(data); | ||
|
||
if (data < node->data) | ||
node->left = insertNode(node->left, data); | ||
else if (data > node->data) | ||
node->right = insertNode(node->right, data); | ||
else | ||
return node; | ||
|
||
|
||
node->height = 1 + max(height(node->left), height(node->right)); | ||
|
||
int balance = getBalance(node); | ||
|
||
|
||
if (balance > 1 && data < node->left->data) | ||
return rightRotate(node); | ||
|
||
if (balance < -1 && data > node->right->data) | ||
return leftRotate(node); | ||
|
||
if (balance > 1 && data > node->left->data) { | ||
node->left = leftRotate(node->left); | ||
return rightRotate(node); | ||
} | ||
|
||
if (balance < -1 && data < node->right->data) { | ||
node->right = rightRotate(node->right); | ||
return leftRotate(node); | ||
} | ||
|
||
return node; | ||
} | ||
|
||
struct Node* findMin(struct Node* node) { | ||
struct Node* current = node; | ||
while (current->left != NULL) | ||
current = current->left; | ||
return current; | ||
} | ||
|
||
struct Node* deleteNode(struct Node* root, int data) { | ||
|
||
if (root == NULL) | ||
return root; | ||
|
||
if (data < root->data) | ||
root->left = deleteNode(root->left, data); | ||
else if (data > root->data) | ||
root->right = deleteNode(root->right, data); | ||
else { | ||
|
||
if (root->left == NULL || root->right == NULL) { | ||
struct Node* temp = root->left ? root->left : root->right; | ||
if (temp == NULL) { | ||
temp = root; | ||
root = NULL; | ||
} else | ||
*root = *temp; | ||
free(temp); | ||
} else { | ||
|
||
struct Node* temp = findMin(root->right); | ||
root->data = temp->data; | ||
root->right = deleteNode(root->right, temp->data); | ||
} | ||
} | ||
|
||
if (root == NULL) | ||
return root; | ||
|
||
root->height = 1 + max(height(root->left), height(root->right)); | ||
|
||
|
||
int balance = getBalance(root); | ||
|
||
|
||
if (balance > 1 && getBalance(root->left) >= 0) | ||
return rightRotate(root); | ||
|
||
if (balance > 1 && getBalance(root->left) < 0) { | ||
root->left = leftRotate(root->left); | ||
return rightRotate(root); | ||
} | ||
|
||
if (balance < -1 && getBalance(root->right) <= 0) | ||
return leftRotate(root); | ||
|
||
if (balance < -1 && getBalance(root->right) > 0) { | ||
root->right = rightRotate(root->right); | ||
return leftRotate(root); | ||
} | ||
|
||
return root; | ||
} | ||
|
||
int searchNode(struct Node* root, int data) { | ||
if (root == NULL) | ||
return 0; | ||
if (data == root->data) | ||
return 1; | ||
else if (data < root->data) | ||
return searchNode(root->left, data); | ||
else | ||
return searchNode(root->right, data); | ||
} | ||
|
||
void inorderTraversal(struct Node* root) { | ||
if (root != NULL) { | ||
inorderTraversal(root->left); | ||
printf("%d -> ", root->data); | ||
inorderTraversal(root->right); | ||
} | ||
} | ||
|
||
int main() { | ||
struct Node* root = NULL; | ||
|
||
root = insertNode(root, 10); | ||
root = insertNode(root, 20); | ||
root = insertNode(root, 30); | ||
root = insertNode(root, 40); | ||
root = insertNode(root, 50); | ||
root = insertNode(root, 25); | ||
|
||
printf("In-order traversal after insertions:\n"); | ||
inorderTraversal(root); | ||
printf("NULL\n"); | ||
|
||
// Deletion | ||
root = deleteNode(root, 20); | ||
printf("In-order traversal after deleting 20:\n"); | ||
inorderTraversal(root); | ||
printf("NULL\n"); | ||
|
||
// Searching | ||
int searchKey = 25; | ||
if (searchNode(root, searchKey)) | ||
printf("Node %d found in the AVL tree.\n", searchKey); | ||
else | ||
printf("Node %d not found in the AVL tree.\n", searchKey); | ||
|
||
return 0; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
# AVL Tree | ||
|
||
## Description | ||
|
||
An AVL Tree is a self-balancing binary search tree (BST) where the height difference (balance factor) between the left and right subtrees of any node is at most 1. This ensures that the tree remains balanced, providing better performance for insertion, deletion, and search operations compared to an unbalanced binary tree. | ||
|
||
### Problem Definition | ||
|
||
The goal is to implement a self-balancing binary search tree (AVL tree) to efficiently support: | ||
|
||
1. Insertion of elements while keeping the tree balanced. | ||
|
||
|
||
2. Deletion of elements, ensuring the balance of the tree is restored if necessary. | ||
|
||
|
||
3. Searching for elements efficiently. | ||
|
||
|
||
4. Tree traversals to visit nodes in specific orders (in-order, pre-order, post-order). | ||
|
||
AVL Property: | ||
|
||
After every insertion or deletion, the balance factor (difference between the heights of the left and right subtrees) of each node must be maintained between -1 and 1. | ||
|
||
### Algorithm Review | ||
|
||
1. Insertion | ||
|
||
Insert the node like in a regular binary search tree (BST). | ||
|
||
After insertion, check the balance factor of every ancestor node. | ||
|
||
If the tree becomes unbalanced, perform one of the following rotations: | ||
|
||
Left Rotation | ||
|
||
Right Rotation | ||
|
||
Left-Right Rotation | ||
|
||
Right-Left Rotation | ||
|
||
|
||
|
||
2. Deletion | ||
|
||
Delete the node like in a regular BST. | ||
|
||
After deletion, check the balance factor of affected nodes. | ||
|
||
If unbalanced, perform the necessary rotation(s) to restore balance. | ||
|
||
|
||
3. Searching | ||
|
||
Same as searching in a binary search tree: move left if the value is smaller, and move right if the value is larger. | ||
|
||
|
||
4. Tree Traversals | ||
|
||
In-order traversal (LNR): Returns elements in sorted order. | ||
|
||
Pre-order traversal (NLR): Visits root first, followed by left and right subtrees. | ||
|
||
Post-order traversal (LRN): Visits children first, followed by root. | ||
|
||
|
||
5. Rotations | ||
|
||
Single Rotations (Left or Right) are used when the tree is unbalanced on one side. | ||
|
||
Double Rotations (Left-Right or Right-Left) are used when the tree is unbalanced in both directions. | ||
|
||
Time Complexity | ||
|
||
In an AVL tree, the height is always maintained as O(log n), ensuring efficient operations: | ||
|
||
Insertion: O(log n) | ||
|
||
Insertion may involve O(log n) rotations to rebalance the tree. | ||
|
||
|
||
Deletion: O(log n) | ||
|
||
Deletion may require O(log n) rotations to restore balance. | ||
|
||
Search: O(log n) | ||
|
||
The tree remains balanced, so the search operation takes logarithmic time. | ||
|
||
Traversal: O(n) |
Oops, something went wrong.