Skip to content

Commit b31bc86

Browse files
authored
Enhance docs, add tests in AVLTree (#6058)
1 parent e94be71 commit b31bc86

File tree

3 files changed

+184
-62
lines changed

3 files changed

+184
-62
lines changed

DIRECTORY.md

+1
Original file line numberDiff line numberDiff line change
@@ -912,6 +912,7 @@
912912
* [StackArrayTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/stacks/StackArrayTest.java)
913913
* [StackOfLinkedListTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/stacks/StackOfLinkedListTest.java)
914914
* trees
915+
* [AVLTreeTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/trees/AVLTreeTest.java)
915916
* [BinaryTreeTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/trees/BinaryTreeTest.java)
916917
* [BoundaryTraversalTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/trees/BoundaryTraversalTest.java)
917918
* [BSTFromSortedArrayTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/trees/BSTFromSortedArrayTest.java)

src/main/java/com/thealgorithms/datastructures/trees/AVLTree.java

+82-62
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,19 @@
11
package com.thealgorithms.datastructures.trees;
22

3+
import java.util.ArrayList;
4+
import java.util.List;
5+
6+
/**
7+
* Represents an AVL Tree, a self-balancing binary search tree.
8+
* In an AVL tree, the heights of the two child subtrees of any node
9+
* differ by at most one. If they differ by more than one at any time,
10+
* rebalancing is performed to restore this property.
11+
*/
312
public class AVLTree {
413

514
private Node root;
615

7-
private class Node {
8-
16+
private static class Node {
917
private int key;
1018
private int balance;
1119
private int height;
@@ -17,8 +25,18 @@ private class Node {
1725
key = k;
1826
parent = p;
1927
}
28+
29+
public Integer getBalance() {
30+
return balance;
31+
}
2032
}
2133

34+
/**
35+
* Inserts a new key into the AVL tree.
36+
*
37+
* @param key the key to be inserted
38+
* @return {@code true} if the key was inserted, {@code false} if the key already exists
39+
*/
2240
public boolean insert(int key) {
2341
if (root == null) {
2442
root = new Node(key, null);
@@ -31,7 +49,6 @@ public boolean insert(int key) {
3149
}
3250

3351
parent = n;
34-
3552
boolean goLeft = n.key > key;
3653
n = goLeft ? n.left : n.right;
3754

@@ -49,8 +66,32 @@ public boolean insert(int key) {
4966
return true;
5067
}
5168

69+
/**
70+
* Deletes a key from the AVL tree.
71+
*
72+
* @param delKey the key to be deleted
73+
*/
74+
public void delete(int delKey) {
75+
if (root == null) {
76+
return;
77+
}
78+
79+
// Find the node to be deleted
80+
Node node = root;
81+
Node child = root;
82+
while (child != null) {
83+
node = child;
84+
child = delKey >= node.key ? node.right : node.left;
85+
if (delKey == node.key) {
86+
delete(node);
87+
return;
88+
}
89+
}
90+
}
91+
5292
private void delete(Node node) {
5393
if (node.left == null && node.right == null) {
94+
// Leaf node
5495
if (node.parent == null) {
5596
root = null;
5697
} else {
@@ -64,6 +105,8 @@ private void delete(Node node) {
64105
}
65106
return;
66107
}
108+
109+
// Node has one or two children
67110
Node child;
68111
if (node.left != null) {
69112
child = node.left;
@@ -80,26 +123,49 @@ private void delete(Node node) {
80123
delete(child);
81124
}
82125

83-
public void delete(int delKey) {
84-
if (root == null) {
85-
return;
126+
/**
127+
* Returns a list of balance factors for each node in the tree.
128+
*
129+
* @return a list of integers representing the balance factors of the nodes
130+
*/
131+
public List<Integer> returnBalance() {
132+
List<Integer> balances = new ArrayList<>();
133+
returnBalance(root, balances);
134+
return balances;
135+
}
136+
137+
private void returnBalance(Node n, List<Integer> balances) {
138+
if (n != null) {
139+
returnBalance(n.left, balances);
140+
balances.add(n.getBalance());
141+
returnBalance(n.right, balances);
86142
}
87-
Node node = root;
88-
Node child = root;
143+
}
89144

90-
while (child != null) {
91-
node = child;
92-
child = delKey >= node.key ? node.right : node.left;
93-
if (delKey == node.key) {
94-
delete(node);
95-
return;
96-
}
145+
/**
146+
* Searches for a key in the AVL tree.
147+
*
148+
* @param key the key to be searched
149+
* @return true if the key is found, false otherwise
150+
*/
151+
public boolean search(int key) {
152+
Node result = searchHelper(this.root, key);
153+
return result != null;
154+
}
155+
156+
private Node searchHelper(Node root, int key) {
157+
if (root == null || root.key == key) {
158+
return root;
97159
}
160+
161+
if (root.key > key) {
162+
return searchHelper(root.left, key);
163+
}
164+
return searchHelper(root.right, key);
98165
}
99166

100167
private void rebalance(Node n) {
101168
setBalance(n);
102-
103169
if (n.balance == -2) {
104170
if (height(n.left.left) >= height(n.left.right)) {
105171
n = rotateRight(n);
@@ -143,7 +209,6 @@ private Node rotateLeft(Node a) {
143209
}
144210

145211
setBalance(a, b);
146-
147212
return b;
148213
}
149214

@@ -169,7 +234,6 @@ private Node rotateRight(Node a) {
169234
}
170235

171236
setBalance(a, b);
172-
173237
return b;
174238
}
175239

@@ -197,53 +261,9 @@ private void setBalance(Node... nodes) {
197261
}
198262
}
199263

200-
public void printBalance() {
201-
printBalance(root);
202-
}
203-
204-
private void printBalance(Node n) {
205-
if (n != null) {
206-
printBalance(n.left);
207-
System.out.printf("%s ", n.balance);
208-
printBalance(n.right);
209-
}
210-
}
211-
212264
private void reheight(Node node) {
213265
if (node != null) {
214266
node.height = 1 + Math.max(height(node.left), height(node.right));
215267
}
216268
}
217-
218-
public boolean search(int key) {
219-
Node result = searchHelper(this.root, key);
220-
return result != null;
221-
}
222-
223-
private Node searchHelper(Node root, int key) {
224-
// root is null or key is present at root
225-
if (root == null || root.key == key) {
226-
return root;
227-
}
228-
229-
// key is greater than root's key
230-
if (root.key > key) {
231-
return searchHelper(root.left, key); // call the function on the node's left child
232-
}
233-
// key is less than root's key then
234-
// call the function on the node's right child as it is greater
235-
return searchHelper(root.right, key);
236-
}
237-
238-
public static void main(String[] args) {
239-
AVLTree tree = new AVLTree();
240-
241-
System.out.println("Inserting values 1 to 10");
242-
for (int i = 1; i < 10; i++) {
243-
tree.insert(i);
244-
}
245-
246-
System.out.print("Printing balance: ");
247-
tree.printBalance();
248-
}
249269
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
package com.thealgorithms.datastructures.trees;
2+
3+
import static org.junit.jupiter.api.Assertions.assertEquals;
4+
import static org.junit.jupiter.api.Assertions.assertFalse;
5+
import static org.junit.jupiter.api.Assertions.assertTrue;
6+
7+
import java.util.List;
8+
import org.junit.jupiter.api.BeforeEach;
9+
import org.junit.jupiter.api.Test;
10+
11+
public class AVLTreeTest {
12+
private AVLTree avlTree;
13+
14+
@BeforeEach
15+
public void setUp() {
16+
avlTree = new AVLTree();
17+
}
18+
19+
@Test
20+
public void testInsert() {
21+
assertTrue(avlTree.insert(10));
22+
assertTrue(avlTree.insert(20));
23+
assertTrue(avlTree.insert(5));
24+
assertFalse(avlTree.insert(10)); // Duplicate
25+
}
26+
27+
@Test
28+
public void testSearch() {
29+
avlTree.insert(15);
30+
avlTree.insert(25);
31+
assertTrue(avlTree.search(15));
32+
assertFalse(avlTree.search(30)); // Not in the tree
33+
}
34+
35+
@Test
36+
public void testDeleteLeafNode() {
37+
avlTree.insert(10);
38+
avlTree.insert(20);
39+
avlTree.insert(30);
40+
avlTree.delete(30);
41+
assertFalse(avlTree.search(30));
42+
}
43+
44+
@Test
45+
public void testDeleteNodeWithOneChild() {
46+
avlTree.insert(20);
47+
avlTree.insert(10);
48+
avlTree.insert(30);
49+
avlTree.delete(10);
50+
assertFalse(avlTree.search(10));
51+
}
52+
53+
@Test
54+
public void testDeleteNodeWithTwoChildren() {
55+
avlTree.insert(20);
56+
avlTree.insert(10);
57+
avlTree.insert(30);
58+
avlTree.insert(25);
59+
avlTree.delete(20);
60+
assertFalse(avlTree.search(20));
61+
assertTrue(avlTree.search(30));
62+
assertTrue(avlTree.search(25));
63+
}
64+
65+
@Test
66+
public void testReturnBalance() {
67+
avlTree.insert(10);
68+
avlTree.insert(20);
69+
avlTree.insert(5);
70+
List<Integer> balances = avlTree.returnBalance();
71+
assertEquals(3, balances.size()); // There should be 3 nodes
72+
assertEquals(0, balances.get(0)); // Balance for node 5
73+
assertEquals(0, balances.get(1)); // Balance for node 10
74+
assertEquals(0, balances.get(2)); // Balance for node 20
75+
}
76+
77+
@Test
78+
public void testInsertAndRebalance() {
79+
avlTree.insert(30);
80+
avlTree.insert(20);
81+
avlTree.insert(10); // This should cause a right rotation
82+
assertTrue(avlTree.search(20));
83+
assertTrue(avlTree.search(10));
84+
assertTrue(avlTree.search(30));
85+
}
86+
87+
@Test
88+
public void testComplexInsertionAndDeletion() {
89+
avlTree.insert(30);
90+
avlTree.insert(20);
91+
avlTree.insert(10);
92+
avlTree.insert(25);
93+
avlTree.insert(5);
94+
avlTree.insert(15);
95+
96+
avlTree.delete(20); // Test deletion
97+
assertFalse(avlTree.search(20));
98+
assertTrue(avlTree.search(30));
99+
assertTrue(avlTree.search(25));
100+
}
101+
}

0 commit comments

Comments
 (0)