Problem Statement

The task is to implement an AVL tree with operations such as insertion and in-order traversal to display the elements in sorted order.

Key Concepts

  1. Node Structure: Each node will contain a value, pointers to its left and right children, and a height attribute.
  2. Height Calculation: The height of a node is defined as the longest path from that node to a leaf.
  3. Balancing: After each insertion, the tree must be balanced. This involves checking the balance factor (difference in height between left and right subtrees) and performing rotations if necessary.

Operations

  1. Insertion: Insert a new value while maintaining the binary search tree properties and balancing the tree.
  2. Rotations: Use single and double rotations to rebalance the tree:
    • Right Rotation
    • Left Rotation
    • Left-Right Rotation
    • Right-Left Rotation
  3. In-Order Traversal: This will allow us to see the elements of the AVL tree in sorted order.

C Program for AVL Tree

Here’s a complete C program to implement an AVL tree:

#include <stdio.h>
#include <stdlib.h>

// Structure for an AVL tree node
struct AVLNode {
    int key;
    struct AVLNode *left;
    struct AVLNode *right;
    int height;
};

// Function to get the height of the node
int height(struct AVLNode *N) {
    if (N == NULL) return 0;
    return N->height;
}

// Function to get the maximum of two integers
int max(int a, int b) {
    return (a > b) ? a : b;
}

// Function to create a new AVL node
struct AVLNode* newNode(int key) {
    struct AVLNode* node = (struct AVLNode*)malloc(sizeof(struct AVLNode));
    node->key = key;
    node->left = NULL;
    node->right = NULL;
    node->height = 1; // New node is initially added at leaf
    return node;
}

// Right rotate the subtree rooted with y
struct AVLNode* rightRotate(struct AVLNode *y) {
    struct AVLNode *x = y->left;
    struct AVLNode *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;
}

// Left rotate the subtree rooted with x
struct AVLNode* leftRotate(struct AVLNode *x) {
    struct AVLNode *y = x->right;
    struct AVLNode *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;
}

// Get the balance factor of the node
int getBalance(struct AVLNode *N) {
    if (N == NULL) return 0;
    return height(N->left) - height(N->right);
}

// Function to insert a key in the subtree rooted with node and returns the new root of the subtree
struct AVLNode* insert(struct AVLNode* node, int key) {
    // 1. Perform the normal BST insert
    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 {
        return node; // Duplicates are not allowed
    }

    // 2. Update the height of this ancestor node
    node->height = 1 + max(height(node->left), height(node->right));

    // 3. Get the balance factor of this ancestor node to check whether it 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;
}

// Function for in-order traversal
void inOrder(struct AVLNode *root) {
    if (root != NULL) {
        inOrder(root->left);
        printf("%d ", root->key);
        inOrder(root->right);
    }
}

// Main function
int main() {
    struct AVLNode *root = NULL;

    int n, key;
    printf("Enter the number of elements to insert: ");
    scanf("%d", &n);

    printf("Enter %d elements:\n", n);
    for (int i = 0; i < n; i++) {
        scanf("%d", &key);
        root = insert(root, key);
    }

    printf("In-order traversal of the AVL tree:\n");
    inOrder(root);
    printf("\n");

    return 0;
}

Explanation of the Code

  1. Node Structure:
    • Each node has a key, pointers to its left and right children, and a height attribute.
  2. Height and Balance Functions:
    • The height function returns the height of a node.
    • The getBalance function calculates the balance factor of a node (left height – right height).
  3. Rotations:
    • The program implements right and left rotations to maintain the AVL tree properties.
  4. Insertion:
    • The insert function adds a new key while ensuring the tree remains balanced after each insertion.
  5. In-Order Traversal:
    • The inOrder function prints the keys in ascending order by recursively traversing the left subtree, then the current node, and finally the right subtree.
  6. Main Function:
    • The main function allows the user to input multiple elements, inserting each into the AVL tree and then performing an in-order traversal to display the sorted elements.

Input and Output Example

Input

codeEnter the number of elements to insert: 7
Enter 7 elements:
10 20 30 40 50 25 5

Output

codeIn-order traversal of the AVL tree:
5 10 20 25 30 40 50

Explanation of the Output

In this case, the user inserts the elements into the AVL tree. The in-order traversal outputs the keys in sorted order, demonstrating that the tree maintains its properties as a binary search tree.

Conclusion

This C program effectively implements an AVL tree, allowing for efficient insertion and in-order traversal. The balancing mechanism ensures that operations remain efficient even as elements are added, making AVL trees a robust choice for maintaining ordered data. You can experiment with different sets of inputs to see how the AVL tree adjusts itself and maintains balance.

Leave a Reply

Your email address will not be published. Required fields are marked *

Verified by MonsterInsights