Introduction
An AVL Tree is a self-balancing binary search tree (BST) where the difference in heights of the left and right subtrees (called the balance factor) is at most 1 for every node. AVL Trees maintain balance by performing rotations (single or double) when nodes are inserted or deleted, ensuring that the tree remains balanced for efficient search, insertion, and deletion operations.
In an AVL Tree:
- Insertion: When a new node is inserted, the tree may become unbalanced. Rotations are used to restore balance.
- Balance Factor: The balance factor of a node is the height difference between its left and right subtrees. The balance factor can be -1, 0, or 1 for a balanced node.
- Rotations: There are four types of rotations:
- Left Rotation.
- Right Rotation.
- Left-Right Rotation (double rotation).
- Right-Left Rotation (double rotation).
This guide will walk you through writing a JavaScript program to implement an AVL Tree with basic operations such as insertion and in-order traversal.
Problem Statement
Create a JavaScript program that:
- Implements an AVL Tree with methods for:
- Insertion: Insert a node into the AVL Tree while maintaining balance.
- In-order Traversal: Traverse the tree in sorted order.
Example:
- Input: Insert nodes
10, 20, 30, 40, 50, 25
- Output (in-order traversal):
10, 20, 25, 30, 40, 50
Solution Steps
- Define a Node Class: Create a class to represent each node with a value, height, left child, and right child.
- Define an AVL Tree Class: Implement methods for:
- Insert: Insert a node into the tree while maintaining balance using rotations.
- Rotations: Perform left and right rotations to maintain balance.
- Height and Balance Factor: Calculate the height and balance factor of each node.
- In-order Traversal: Traverse the tree in sorted order.
JavaScript Program
Step 1: Define the Node Class
// JavaScript Program to Implement an AVL Tree
// Author: https://www.rameshfadatare.com/
class Node {
constructor(value) {
this.value = value;
this.left = null;
this.right = null;
this.height = 1; // Initially, every node's height is 1
}
}
Step 2: Define the AVL Tree Class
class AVLTree {
constructor() {
this.root = null;
}
// Get the height of the node
height(node) {
if (node === null) {
return 0;
}
return node.height;
}
// Calculate the balance factor of a node
getBalance(node) {
if (node === null) {
return 0;
}
return this.height(node.left) - this.height(node.right);
}
// Right rotate subtree rooted with y
rightRotate(y) {
let x = y.left;
let T2 = x.right;
// Perform rotation
x.right = y;
y.left = T2;
// Update heights
y.height = Math.max(this.height(y.left), this.height(y.right)) + 1;
x.height = Math.max(this.height(x.left), this.height(x.right)) + 1;
// Return new root
return x;
}
// Left rotate subtree rooted with x
leftRotate(x) {
let y = x.right;
let T2 = y.left;
// Perform rotation
y.left = x;
x.right = T2;
// Update heights
x.height = Math.max(this.height(x.left), this.height(x.right)) + 1;
y.height = Math.max(this.height(y.left), this.height(y.right)) + 1;
// Return new root
return y;
}
// Insert a node into the AVL Tree
insert(node, value) {
// Perform normal BST insertion
if (node === null) {
return new Node(value);
}
if (value < node.value) {
node.left = this.insert(node.left, value);
} else if (value > node.value) {
node.right = this.insert(node.right, value);
} else {
// Duplicate values are not allowed in AVL Tree
return node;
}
// Update the height of the ancestor node
node.height = 1 + Math.max(this.height(node.left), this.height(node.right));
// Get the balance factor of this ancestor node
let balance = this.getBalance(node);
// If the node becomes unbalanced, then perform rotations
// Left Left Case
if (balance > 1 && value < node.left.value) {
return this.rightRotate(node);
}
// Right Right Case
if (balance < -1 && value > node.right.value) {
return this.leftRotate(node);
}
// Left Right Case
if (balance > 1 && value > node.left.value) {
node.left = this.leftRotate(node.left);
return this.rightRotate(node);
}
// Right Left Case
if (balance < -1 && value < node.right.value) {
node.right = this.rightRotate(node.right);
return this.leftRotate(node);
}
// Return the (unchanged) node pointer
return node;
}
// In-order traversal of the AVL tree
inOrder(node) {
if (node !== null) {
this.inOrder(node.left);
console.log(node.value);
this.inOrder(node.right);
}
}
// Insert a value into the AVL Tree
insertValue(value) {
this.root = this.insert(this.root, value);
}
}
Step 3: Example Usage
// Example usage of the AVL Tree
const avl = new AVLTree();
// Insert values
avl.insertValue(10);
avl.insertValue(20);
avl.insertValue(30);
avl.insertValue(40);
avl.insertValue(50);
avl.insertValue(25);
// In-order traversal of the AVL Tree
console.log("In-order traversal:");
avl.inOrder(avl.root);
Output Example
In-order traversal:
10
20
25
30
40
50
Explanation
Step 1: Define the Node Class
- The
Node
class represents each node in the AVL Tree. Each node has:value
: The value stored in the node.left
: A reference to the left child node.right
: A reference to the right child node.height
: The height of the node, which helps calculate the balance factor.
Step 2: Define the AVL Tree Class
height()
: Returns the height of a node. If the node isnull
, the height is0
.getBalance()
: Calculates the balance factor of a node by subtracting the height of the right subtree from the height of the left subtree.rightRotate()
andleftRotate()
: Perform right and left rotations to restore balance when the tree becomes unbalanced.insert()
: Inserts a new value into the AVL tree. After the insertion, it updates the height and balance factor of the nodes, performing rotations as necessary to maintain balance.inOrder()
: Performs in-order traversal, printing the values of the nodes in ascending order.
Step 3: Example Usage
- The AVL Tree is created, and values are inserted one by one.
- The in-order traversal prints the values in ascending order.
Time Complexity
- Insertion: O(log n), where
n
is the number of nodes in the AVL Tree.- The tree is balanced, so the height of the tree is
log n
.
- The tree is balanced, so the height of the tree is
- In-order Traversal: O(n), where
n
is the number of nodes in the tree.
Conclusion
This JavaScript program implements an AVL Tree, a self-balancing binary search tree that ensures efficient operations even after multiple insertions. The tree uses rotations to maintain balance, providing logarithmic time complexity for insertion, deletion, and search operations.
Comments
Post a Comment
Leave Comment