Skip to content

Commit 646b998

Browse files
Added AVL tree implementation with detailed comments
1 parent 3541571 commit 646b998

File tree

4 files changed

+250
-394
lines changed

4 files changed

+250
-394
lines changed

src/main/java/com/thealgorithms/tree/AVL.java

Lines changed: 64 additions & 148 deletions
Original file line numberDiff line numberDiff line change
@@ -4,22 +4,8 @@
44
import java.util.List;
55
import java.util.NoSuchElementException;
66

7-
/**
8-
* AVL (Adelson-Velsky and Landis) Tree is a self-balancing Binary Search Tree.
9-
* Operations supported:
10-
* - insert, delete, search
11-
* - inorder, preorder, postorder traversal
12-
* - findMin(), findMax()
13-
*
14-
* Properties:
15-
* - For every node: |height(left) - height(right)| <= 1
16-
* - Maintains O(log n) time complexity for insert/delete/search
17-
*/
187
public class AVL {
198

20-
/**
21-
* Inner class to represent a node in AVL Tree
22-
*/
239
private static class Node {
2410
int key;
2511
int height;
@@ -28,263 +14,230 @@ private static class Node {
2814

2915
Node(int key) {
3016
this.key = key;
31-
this.height = 1; // New node starts as a leaf node with height = 1
17+
left = right = null;
18+
this.height = 1;
3219
}
3320
}
3421

35-
// Root node of the AVL Tree
3622
private Node root;
3723

38-
// Constructor
3924
public AVL() {
4025
root = null;
4126
}
4227

43-
/* ======================== PUBLIC METHODS ======================== */
44-
45-
/** Insert a key into the AVL Tree */
4628
public void insert(int key) {
4729
root = insertRecursive(root, key);
4830
}
4931

50-
/** Delete a key from the AVL Tree */
5132
public void delete(int key) {
5233
root = deleteRecursive(root, key);
5334
}
5435

55-
/** Search a key in the AVL Tree */
5636
public boolean search(int key) {
5737
return searchRecursive(root, key);
5838
}
5939

60-
/** Return the smallest key in the AVL Tree */
6140
public int findMin() {
62-
if (root == null) throw new NoSuchElementException("AVL Tree is empty");
41+
if (root == null) {
42+
throw new NoSuchElementException("AVL Tree is empty");
43+
}
6344
return findMinNode(root).key;
6445
}
6546

66-
/** Return the largest key in the AVL Tree */
6747
public int findMax() {
68-
if (root == null) throw new NoSuchElementException("AVL Tree is empty");
48+
if (root == null) {
49+
throw new NoSuchElementException("AVL Tree is empty");
50+
}
6951
Node cur = root;
70-
while (cur.right != null) cur = cur.right;
52+
while (cur.right != null) {
53+
cur = cur.right;
54+
}
7155
return cur.key;
7256
}
7357

74-
/** Print nodes in Inorder (sorted order) */
7558
public void printInorder() {
7659
System.out.print("Inorder: ");
7760
printInorderRecursive(root);
7861
System.out.println();
7962
}
8063

81-
/** Print nodes in Preorder (Root → Left → Right) */
8264
public void printPreorder() {
8365
System.out.print("Preorder: ");
8466
printPreorderRecursive(root);
8567
System.out.println();
8668
}
8769

88-
/** Print nodes in Postorder (Left → Right → Root) */
8970
public void printPostorder() {
9071
System.out.print("Postorder: ");
9172
printPostorderRecursive(root);
9273
System.out.println();
9374
}
9475

95-
/** Return Inorder list (useful for testing) */
9676
public List<Integer> inorderList() {
9777
List<Integer> res = new ArrayList<>();
9878
inorderToList(root, res);
9979
return res;
10080
}
10181

102-
/** Return Preorder list (useful for testing) */
10382
public List<Integer> preorderList() {
10483
List<Integer> res = new ArrayList<>();
10584
preorderToList(root, res);
10685
return res;
10786
}
10887

109-
/** Return Postorder list (useful for testing) */
11088
public List<Integer> postorderList() {
11189
List<Integer> res = new ArrayList<>();
11290
postorderToList(root, res);
11391
return res;
11492
}
11593

116-
/**
117-
* Recursive insert:
118-
* 1. Insert key like a normal BST
119-
* 2. Update height of current node
120-
* 3. Balance the node if it became unbalanced
121-
*/
12294
private Node insertRecursive(Node node, int key) {
123-
// Step 1: Perform standard BST insert
12495
if (node == null) {
12596
return new Node(key);
12697
}
12798

128-
if (key < node.key)
99+
if (key < node.key) {
129100
node.left = insertRecursive(node.left, key);
130-
else if (key > node.key)
101+
} else if (key > node.key) {
131102
node.right = insertRecursive(node.right, key);
132-
else
133-
return node; // Duplicates not allowed
103+
} else {
104+
return node;
105+
}
134106

135-
// Step 2: Update height of ancestor node
136107
updateHeight(node);
137-
138-
// Step 3: Balance the node and return new root
139108
return balanceNode(node);
140109
}
141110

142-
/**
143-
* Recursive delete:
144-
* 1. Perform normal BST delete
145-
* 2. Update height of current node
146-
* 3. Balance it if necessary
147-
*/
148111
private Node deleteRecursive(Node node, int key) {
149-
if (node == null) return null;
112+
if (node == null) {
113+
return null;
114+
}
150115

151-
// Step 1: Perform BST delete
152-
if (key < node.key)
116+
if (key < node.key) {
153117
node.left = deleteRecursive(node.left, key);
154-
else if (key > node.key)
118+
} else if (key > node.key) {
155119
node.right = deleteRecursive(node.right, key);
156-
else {
157-
// Node found
120+
} else {
158121
if (node.left == null || node.right == null) {
159-
Node temp = (node.left != null) ? node.left : node.right;
122+
Node temp = null;
123+
if (node.left != null) {
124+
temp = node.left;
125+
} else {
126+
temp = node.right;
127+
}
160128

161-
// No child case
162129
if (temp == null) {
163130
node = null;
164131
} else {
165132
node = temp;
166133
}
167134
} else {
168-
// Node with two children → get inorder successor
169135
Node successor = findMinNode(node.right);
170136
node.key = successor.key;
171137
node.right = deleteRecursive(node.right, successor.key);
172138
}
173139
}
174140

175-
// If tree had only one node
176-
if (node == null) return null;
141+
if (node == null) {
142+
return null;
143+
}
177144

178-
// Step 2: Update height
179145
updateHeight(node);
180-
181-
// Step 3: Rebalance node
182146
return balanceNode(node);
183147
}
184148

185-
/** Recursive search like normal BST */
186149
private boolean searchRecursive(Node node, int key) {
187-
if (node == null) return false;
188-
if (key == node.key) return true;
189-
return key < node.key ? searchRecursive(node.left, key) : searchRecursive(node.right, key);
150+
if (node == null) {
151+
return false;
152+
}
153+
if (key == node.key) {
154+
return true;
155+
}
156+
if (key < node.key) {
157+
return searchRecursive(node.left, key);
158+
} else {
159+
return searchRecursive(node.right, key);
160+
}
190161
}
191162

192-
/** Find node with minimum key */
193163
private Node findMinNode(Node node) {
194164
Node cur = node;
195-
while (cur.left != null) cur = cur.left;
165+
while (cur.left != null) {
166+
cur = cur.left;
167+
}
196168
return cur;
197169
}
198170

199-
/* ======================== ROTATIONS & BALANCING ======================== */
200-
201-
/** Right rotation (used in LL or LR imbalance) */
202171
private Node rightRotate(Node y) {
203172
Node x = y.left;
204173
Node T2 = x.right;
205174

206-
// Perform rotation
207175
x.right = y;
208176
y.left = T2;
209177

210-
// Update heights
211178
updateHeight(y);
212179
updateHeight(x);
213180

214-
return x; // New root
181+
return x;
215182
}
216183

217-
/** Left rotation (used in RR or RL imbalance) */
218184
private Node leftRotate(Node x) {
219185
Node y = x.right;
220186
Node T2 = y.left;
221187

222-
// Perform rotation
223188
y.left = x;
224189
x.right = T2;
225190

226-
// Update heights
227191
updateHeight(x);
228192
updateHeight(y);
229193

230-
return y; // New root
194+
return y;
231195
}
232196

233-
/**
234-
* Balances a node by checking its balance factor:
235-
*
236-
* - If > 1 → left heavy
237-
* - If < -1 → right heavy
238-
*
239-
* Depending on the case, we do:
240-
* - LL → Right Rotate
241-
* - RR → Left Rotate
242-
* - LR → Left Rotate child + Right Rotate
243-
* - RL → Right Rotate child + Left Rotate
244-
*/
245197
private Node balanceNode(Node node) {
246198
int balance = getBalance(node);
247199

248-
// Case 1: Left Left (LL)
249-
if (balance > 1 && getBalance(node.left) >= 0) return rightRotate(node);
200+
if (balance > 1 && getBalance(node.left) >= 0) {
201+
return rightRotate(node);
202+
}
250203

251-
// Case 2: Left Right (LR)
252204
if (balance > 1 && getBalance(node.left) < 0) {
253205
node.left = leftRotate(node.left);
254206
return rightRotate(node);
255207
}
256208

257-
// Case 3: Right Right (RR)
258-
if (balance < -1 && getBalance(node.right) <= 0) return leftRotate(node);
209+
if (balance < -1 && getBalance(node.right) <= 0) {
210+
return leftRotate(node);
211+
}
259212

260-
// Case 4: Right Left (RL)
261213
if (balance < -1 && getBalance(node.right) > 0) {
262214
node.right = rightRotate(node.right);
263215
return leftRotate(node);
264216
}
265217

266-
return node; // Already balanced
218+
return node;
267219
}
268220

269-
/* ======================== HELPER FUNCTIONS ======================== */
270-
271-
/** Returns height of a node */
272221
private int height(Node node) {
273-
return node == null ? 0 : node.height;
222+
if (node == null) {
223+
return 0;
224+
} else {
225+
return node.height;
226+
}
274227
}
275228

276-
/** Updates height of a node based on its children */
277229
private void updateHeight(Node node) {
278230
node.height = 1 + Math.max(height(node.left), height(node.right));
279231
}
280232

281-
/** Calculates balance factor = height(left) - height(right) */
282233
private int getBalance(Node node) {
283-
return node == null ? 0 : height(node.left) - height(node.right);
234+
if (node == null) {
235+
return 0;
236+
} else {
237+
return height(node.left) - height(node.right);
238+
}
284239
}
285240

286-
/* ======================== TRAVERSALS ======================== */
287-
288241
private void printInorderRecursive(Node node) {
289242
if (node == null) {
290243
return;
@@ -338,41 +291,4 @@ private void postorderToList(Node node, List<Integer> out) {
338291
postorderToList(node.right, out);
339292
out.add(node.key);
340293
}
341-
342-
public static void main(String[] args) {
343-
AVL avl = new AVL();
344-
345-
int[] values = {30, 20, 40, 10, 25, 35, 50, 5, 15, 27, 45, 60};
346-
347-
// Insert all values one by one
348-
for (int v : values) avl.insert(v);
349-
350-
// Display traversals
351-
avl.printInorder(); // should show sorted order
352-
avl.printPreorder();
353-
avl.printPostorder();
354-
355-
// Display traversal lists
356-
System.out.println("Inorder List: " + avl.inorderList());
357-
System.out.println("Preorder List: " + avl.preorderList());
358-
System.out.println("Postorder List: " + avl.postorderList());
359-
360-
// Search examples
361-
System.out.println("Search 27: " + avl.search(27)); // true
362-
System.out.println("Search 99: " + avl.search(99)); // false
363-
364-
// Min and Max
365-
System.out.println("Min: " + avl.findMin());
366-
System.out.println("Max: " + avl.findMax());
367-
368-
// Delete operations and show tree after each
369-
avl.delete(10);
370-
System.out.println("After deleting 10: " + avl.inorderList());
371-
372-
avl.delete(30);
373-
System.out.println("After deleting 30: " + avl.inorderList());
374-
375-
avl.delete(40);
376-
System.out.println("After deleting 40: " + avl.inorderList());
377-
}
378294
}

0 commit comments

Comments
 (0)