Skip to content

Commit 5e5a5f4

Browse files
committed
Add Binary Search Tree and AVL Tree implementations with tests
1 parent 2588af0 commit 5e5a5f4

File tree

7 files changed

+496
-1
lines changed

7 files changed

+496
-1
lines changed

desktop.ini

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
[.ShellClassInfo]
2+
LocalizedResourceName=@Java,0

pmd-custom_ruleset.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
Custom PMD checks for TheAlgorithms/Java
99
</description>
1010
<rule name="UselessMainMethod"
11-
language="java"
11+
1212
message="The main method is redundant in this context"
1313
class="net.sourceforge.pmd.lang.rule.xpath.XPathRule">
1414
<description>
Lines changed: 207 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,207 @@
1+
package com.thealgorithms.tree;
2+
3+
import java.util.ArrayList;
4+
import java.util.List;
5+
import java.util.Objects;
6+
7+
/**
8+
* Generic AVL Tree (self-balancing BST). Duplicates are handled via a count in each node.
9+
*
10+
* @param <T> key type (must be Comparable)
11+
*/
12+
public class AVLTree<T extends Comparable<T>> {
13+
14+
static class Node<T> {
15+
T key;
16+
Node<T> left, right;
17+
int height;
18+
int count;
19+
20+
Node(T key) {
21+
this.key = key;
22+
this.height = 1;
23+
this.count = 1;
24+
}
25+
}
26+
27+
private Node<T> root;
28+
private int size; // distinct nodes
29+
30+
public AVLTree() {}
31+
32+
// Public API
33+
public void insert(T key) {
34+
Objects.requireNonNull(key);
35+
root = insert(root, key);
36+
}
37+
38+
public boolean contains(T key) {
39+
Objects.requireNonNull(key);
40+
Node<T> cur = root;
41+
while (cur != null) {
42+
int cmp = key.compareTo(cur.key);
43+
if (cmp == 0) return true;
44+
cur = (cmp < 0) ? cur.left : cur.right;
45+
}
46+
return false;
47+
}
48+
49+
public boolean delete(T key) {
50+
Objects.requireNonNull(key);
51+
if (!contains(key)) return false;
52+
root = delete(root, key);
53+
return true;
54+
}
55+
56+
public T findMin() {
57+
if (root == null) return null;
58+
Node<T> cur = root;
59+
while (cur.left != null) cur = cur.left;
60+
return cur.key;
61+
}
62+
63+
public T findMax() {
64+
if (root == null) return null;
65+
Node<T> cur = root;
66+
while (cur.right != null) cur = cur.right;
67+
return cur.key;
68+
}
69+
70+
public List<T> inorder() {
71+
List<T> out = new ArrayList<>();
72+
inorder(root, out);
73+
return out;
74+
}
75+
76+
public int sizeDistinct() {
77+
return size;
78+
}
79+
80+
public int countOccurrences(T key) {
81+
Node<T> cur = root;
82+
while (cur != null) {
83+
int cmp = key.compareTo(cur.key);
84+
if (cmp == 0) return cur.count;
85+
cur = (cmp < 0) ? cur.left : cur.right;
86+
}
87+
return 0;
88+
}
89+
90+
// === Private helpers ===
91+
private Node<T> insert(Node<T> node, T key) {
92+
if (node == null) {
93+
size++;
94+
return new Node<>(key);
95+
}
96+
int cmp = key.compareTo(node.key);
97+
if (cmp < 0) {
98+
node.left = insert(node.left, key);
99+
} else if (cmp > 0) {
100+
node.right = insert(node.right, key);
101+
} else {
102+
node.count++;
103+
return node;
104+
}
105+
106+
updateHeight(node);
107+
return balance(node);
108+
}
109+
110+
private Node<T> delete(Node<T> node, T key) {
111+
if (node == null) return null;
112+
int cmp = key.compareTo(node.key);
113+
if (cmp < 0) {
114+
node.left = delete(node.left, key);
115+
} else if (cmp > 0) {
116+
node.right = delete(node.right, key);
117+
} else {
118+
if (node.count > 1) {
119+
node.count--;
120+
return node;
121+
}
122+
// remove node
123+
size--;
124+
if (node.left == null) return node.right;
125+
if (node.right == null) return node.left;
126+
// two children: replace with successor
127+
Node<T> succ = minNode(node.right);
128+
node.key = succ.key;
129+
node.count = succ.count;
130+
node.right = deleteNodeMin(node.right);
131+
}
132+
updateHeight(node);
133+
return balance(node);
134+
}
135+
136+
private Node<T> minNode(Node<T> node) {
137+
while (node.left != null) node = node.left;
138+
return node;
139+
}
140+
141+
private Node<T> deleteNodeMin(Node<T> node) {
142+
if (node.left == null) return node.right;
143+
node.left = deleteNodeMin(node.left);
144+
updateHeight(node);
145+
return balance(node);
146+
}
147+
148+
private void inorder(Node<T> node, List<T> out) {
149+
if (node == null) return;
150+
inorder(node.left, out);
151+
for (int i = 0; i < node.count; i++) out.add(node.key);
152+
inorder(node.right, out);
153+
}
154+
155+
// --- AVL utilities ---
156+
private int height(Node<T> n) {
157+
return n == null ? 0 : n.height;
158+
}
159+
160+
private void updateHeight(Node<T> n) {
161+
n.height = 1 + Math.max(height(n.left), height(n.right));
162+
}
163+
164+
private int balanceFactor(Node<T> n) {
165+
return (n == null) ? 0 : height(n.left) - height(n.right);
166+
}
167+
168+
private Node<T> balance(Node<T> n) {
169+
int bf = balanceFactor(n);
170+
if (bf > 1) {
171+
if (balanceFactor(n.left) < 0) {
172+
// Left-Right
173+
n.left = rotateLeft(n.left);
174+
}
175+
// Left-Left
176+
return rotateRight(n);
177+
} else if (bf < -1) {
178+
if (balanceFactor(n.right) > 0) {
179+
// Right-Left
180+
n.right = rotateRight(n.right);
181+
}
182+
// Right-Right
183+
return rotateLeft(n);
184+
}
185+
return n;
186+
}
187+
188+
private Node<T> rotateRight(Node<T> y) {
189+
Node<T> x = y.left;
190+
Node<T> T2 = x.right;
191+
x.right = y;
192+
y.left = T2;
193+
updateHeight(y);
194+
updateHeight(x);
195+
return x;
196+
}
197+
198+
private Node<T> rotateLeft(Node<T> x) {
199+
Node<T> y = x.right;
200+
Node<T> T2 = y.left;
201+
y.left = x;
202+
x.right = T2;
203+
updateHeight(x);
204+
updateHeight(y);
205+
return y;
206+
}
207+
}
Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
package com.thealgorithms.tree;
2+
3+
import java.util.ArrayList;
4+
import java.util.List;
5+
import java.util.Objects;
6+
7+
/**
8+
* Generic Binary Search Tree that allows duplicate keys via a counter in each node.
9+
*
10+
* @param <T> key type (must be Comparable)
11+
*/
12+
public class BinarySearchTree<T extends Comparable<T>> {
13+
14+
static class Node<T> {
15+
T key;
16+
Node<T> left, right;
17+
int count; // number of duplicates (>=1)
18+
19+
Node(T key) {
20+
this.key = key;
21+
this.count = 1;
22+
}
23+
}
24+
25+
private Node<T> root;
26+
private int size; // number of distinct nodes (not counting duplicates)
27+
28+
public BinarySearchTree() {}
29+
30+
// Public API
31+
public void insert(T key) {
32+
Objects.requireNonNull(key);
33+
root = insert(root, key);
34+
}
35+
36+
public boolean contains(T key) {
37+
Objects.requireNonNull(key);
38+
Node<T> cur = root;
39+
while (cur != null) {
40+
int cmp = key.compareTo(cur.key);
41+
if (cmp == 0) return true;
42+
cur = (cmp < 0) ? cur.left : cur.right;
43+
}
44+
return false;
45+
}
46+
47+
public boolean delete(T key) {
48+
Objects.requireNonNull(key);
49+
int initialCount = countOccurrences(key);
50+
if (initialCount == 0) return false;
51+
root = delete(root, key);
52+
return countOccurrences(key) < initialCount;
53+
}
54+
55+
public T findMin() {
56+
if (root == null) return null;
57+
Node<T> cur = root;
58+
while (cur.left != null) cur = cur.left;
59+
return cur.key;
60+
}
61+
62+
public T findMax() {
63+
if (root == null) return null;
64+
Node<T> cur = root;
65+
while (cur.right != null) cur = cur.right;
66+
return cur.key;
67+
}
68+
69+
public List<T> inorder() {
70+
List<T> out = new ArrayList<>();
71+
inorder(root, out);
72+
return out;
73+
}
74+
75+
public List<T> preorder() {
76+
List<T> out = new ArrayList<>();
77+
preorder(root, out);
78+
return out;
79+
}
80+
81+
public List<T> postorder() {
82+
List<T> out = new ArrayList<>();
83+
postorder(root, out);
84+
return out;
85+
}
86+
87+
public int sizeDistinct() {
88+
return size;
89+
}
90+
91+
public int countOccurrences(T key) {
92+
Node<T> cur = root;
93+
while (cur != null) {
94+
int cmp = key.compareTo(cur.key);
95+
if (cmp == 0) return cur.count;
96+
cur = (cmp < 0) ? cur.left : cur.right;
97+
}
98+
return 0;
99+
}
100+
101+
// === Private helpers ===
102+
private Node<T> insert(Node<T> node, T key) {
103+
if (node == null) {
104+
size++;
105+
return new Node<>(key);
106+
}
107+
int cmp = key.compareTo(node.key);
108+
if (cmp < 0) {
109+
node.left = insert(node.left, key);
110+
} else if (cmp > 0) {
111+
node.right = insert(node.right, key);
112+
} else {
113+
node.count++;
114+
}
115+
return node;
116+
}
117+
118+
private Node<T> delete(Node<T> node, T key) {
119+
if (node == null) return null;
120+
int cmp = key.compareTo(node.key);
121+
if (cmp < 0) {
122+
node.left = delete(node.left, key);
123+
} else if (cmp > 0) {
124+
node.right = delete(node.right, key);
125+
} else {
126+
// found
127+
if (node.count > 1) {
128+
node.count--;
129+
return node;
130+
}
131+
// remove node
132+
size--;
133+
if (node.left == null) return node.right;
134+
if (node.right == null) return node.left;
135+
// two children: find successor
136+
Node<T> successor = minNode(node.right);
137+
node.key = successor.key;
138+
node.count = successor.count;
139+
// delete successor node (all its counts)
140+
node.right = deleteNodeMin(node.right);
141+
}
142+
return node;
143+
}
144+
145+
private Node<T> minNode(Node<T> node) {
146+
while (node.left != null) node = node.left;
147+
return node;
148+
}
149+
150+
private Node<T> deleteNodeMin(Node<T> node) {
151+
if (node.left == null) return node.right;
152+
node.left = deleteNodeMin(node.left);
153+
return node;
154+
}
155+
156+
private void inorder(Node<T> node, List<T> out) {
157+
if (node == null) return;
158+
inorder(node.left, out);
159+
for (int i = 0; i < node.count; i++) out.add(node.key);
160+
inorder(node.right, out);
161+
}
162+
163+
private void preorder(Node<T> node, List<T> out) {
164+
if (node == null) return;
165+
for (int i = 0; i < node.count; i++) out.add(node.key);
166+
preorder(node.left, out);
167+
preorder(node.right, out);
168+
}
169+
170+
private void postorder(Node<T> node, List<T> out) {
171+
if (node == null) return;
172+
postorder(node.left, out);
173+
postorder(node.right, out);
174+
for (int i = 0; i < node.count; i++) out.add(node.key);
175+
}
176+
}

0 commit comments

Comments
 (0)