Skip to content

Commit 2a8022b

Browse files
committed
Add BinarySearchTree and corresponding Node implementation
1 parent 107229a commit 2a8022b

File tree

2 files changed

+403
-0
lines changed

2 files changed

+403
-0
lines changed
Lines changed: 366 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,366 @@
1+
package dataStructures.binarySearchTree;
2+
3+
import java.util.*;
4+
5+
/**
6+
* Implementation of Binary Search Tree.
7+
* @param <T> generic type of object to be stored; must be comparable
8+
* client methods:
9+
* root()
10+
* insert(T key)
11+
* delete(T key)
12+
* search(T key)
13+
* predecessor(T key)
14+
* successor(T key)
15+
* findMax()
16+
* findMin()
17+
* printInorder()
18+
* printPreorder()
19+
* printPostorder()
20+
* printLevelorder()
21+
*/
22+
public class BinarySearchTree<T extends Comparable<T>, V> {
23+
24+
private Node<T, V> root;
25+
26+
/**
27+
* Insert a key-value pair into the tree rooted at a specified node.
28+
* NOTE: ASSUMPTION THAT NO TWO NODES SHARE THE SAME KEY VALUE.
29+
* @param node the (sub)tree rooted at node which the key will be inserted into
30+
* @param key the key to insert
31+
* @param value the value tied to the key to insert
32+
*/
33+
private void insert(Node<T, V> node, T key, V value) {
34+
if (node.key.compareTo(key) < 0) {
35+
if (node.right == null) {
36+
node.right = new Node<>(key, value);
37+
} else {
38+
insert(node.right, key, value);
39+
}
40+
} else if (node.key.compareTo(key) > 0) {
41+
if (node.left == null) {
42+
node.left = new Node<>(key, value);
43+
} else {
44+
insert(node.left, key, value);
45+
}
46+
} else {
47+
throw new RuntimeException("Duplicate key not supported!");
48+
}
49+
}
50+
51+
/**
52+
* Delete a key from the binary search tree rooted at a specified node.
53+
* Find the node that holds the key and remove the node from the tree.
54+
* @param node the (sub)tree rooted at node which the key will be deleted from
55+
* @param key the key to remove
56+
* @return the (new) root which the tree is rooted at after rebalancing
57+
*/
58+
private Node<T, V> delete(Node<T, V> node, T key) {
59+
if (node.key.compareTo(key) < 0) { // key > current node
60+
if (node.right == null) {
61+
throw new RuntimeException("Key does not exist!");
62+
} else {
63+
node.right = delete(node.right, key);
64+
}
65+
} else if (node.key.compareTo(key) > 0) { // key < current node
66+
if (node.left == null) {
67+
throw new RuntimeException("Key does not exist!");
68+
} else {
69+
node.left = delete(node.left, key);
70+
}
71+
} else {
72+
if (node.left == null && node.right == null) { // 0 child case
73+
node = null;
74+
} else if (node.left == null || node.right == null) { // 1 child case
75+
if (node.right != null) {
76+
node.right.parent = node.parent;
77+
return node.right;
78+
} else {
79+
node.left.parent = node.parent;
80+
return node.left;
81+
}
82+
} else { // 2-children case
83+
T successorKey = successor(key);
84+
Node<T, V> successor = search(successorKey);
85+
86+
// replaces the current node with successor
87+
node.key = successor.key;
88+
node.value = successor.value;
89+
90+
// delete the original successor
91+
// successor will definitely be in right subtree of current node and not an ancestor
92+
node.right = delete(node.right, successor.key);
93+
}
94+
}
95+
96+
return node;
97+
}
98+
99+
/**
100+
* Find the left-most child of the (sub)tree rooted at a specified node
101+
* @param n tree is rooted at this node
102+
* @return left-most node
103+
*/
104+
private Node<T, V> getMostLeft(Node<T, V> n) {
105+
if (n.left == null) {
106+
return n;
107+
} else {
108+
return getMostLeft(n.left);
109+
}
110+
}
111+
112+
private Node<T, V> getMostRight(Node<T, V> n) {
113+
if (n.right == null) {
114+
return n;
115+
} else {
116+
return getMostRight(n.right);
117+
}
118+
}
119+
120+
/**
121+
* Find the key of the predecessor of a specified node that exists in the tree
122+
* NOTE: the input node is assumed to be in the tree
123+
* @param node node that exists in the tree
124+
* @return key value; null if node has no predecessor
125+
*/
126+
private T predecessor(Node<T, V> node) {
127+
Node<T, V> curr = node;
128+
if (curr.left != null) { // predecessor in children
129+
return getMostRight(curr.left).key;
130+
} else { // predecessor in ancestor
131+
while (curr != null) {
132+
if (curr.key.compareTo(node.key) < 0) {
133+
return curr.key;
134+
}
135+
curr = curr.parent;
136+
}
137+
}
138+
return null;
139+
}
140+
141+
/**
142+
* Find the key of the successor of a specified node that exists in the tree
143+
* NOTE: the input node is assumed to be in the tree
144+
* @param node node that exists in the tree
145+
* @return key value; null if node has no successor
146+
*/
147+
private T successor(Node<T, V> node) {
148+
Node<T, V> curr = node;
149+
if (curr.right != null) { // successor in children
150+
return getMostLeft(curr.right).key;
151+
} else { // successor in ancestor
152+
while (curr != null) {
153+
if (curr.key.compareTo(node.key) > 0) { // finds the cloests
154+
return curr.key;
155+
}
156+
curr = curr.parent;
157+
}
158+
}
159+
return null;
160+
}
161+
162+
/**
163+
* Prints out in-order traversal of tree rooted at node
164+
* @param node node which the tree is rooted at
165+
*/
166+
private void printInorder(Node<T, V> node) {
167+
if (node == null) {
168+
return;
169+
}
170+
171+
if (node.left != null) {
172+
printInorder(node.left);
173+
}
174+
175+
System.out.print(node.toString() + " ");
176+
177+
if (node.right != null) {
178+
printInorder(node.right);
179+
}
180+
}
181+
182+
/**
183+
* Prints out pre-order traversal of tree rooted at node
184+
* @param node node which the tree is rooted at
185+
*/
186+
private void printPreorder(Node<T, V> node) {
187+
if (node == null) {
188+
return;
189+
}
190+
191+
System.out.print(node.toString() + " ");
192+
193+
if (node.left != null) {
194+
printPreorder(node.left);
195+
}
196+
197+
if (node.right != null) {
198+
printPreorder(node.right);
199+
}
200+
}
201+
202+
/**
203+
* Prints out post-order traversal of tree rooted at node
204+
* @param node node which the tree is rooted at
205+
*/
206+
private void printPostorder(Node<T, V> node) {
207+
if (node == null) {
208+
return;
209+
}
210+
211+
if (node.left != null) {
212+
printPostorder(node.left);
213+
}
214+
215+
if (node.right != null) {
216+
printPostorder(node.right);
217+
}
218+
219+
System.out.print(node.toString() + " ");
220+
}
221+
222+
/**
223+
* Prints out level-order traversal of tree rooted at node
224+
* @param node node which the tree is rooted at
225+
*/
226+
private void printLevelorder(Node<T, V> node) {
227+
if (node == null) {
228+
return;
229+
}
230+
Queue<Node<T, V>> q = new LinkedList<>();
231+
q.add(node);
232+
while (!q.isEmpty()) {
233+
Node<T, V> curr = q.poll();
234+
System.out.print(curr.toString() + " ");
235+
if (curr.left != null) {
236+
q.add(curr.left);
237+
}
238+
if (curr.right != null) {
239+
q.add(curr.right);
240+
}
241+
}
242+
}
243+
244+
/**
245+
* Get root of tree.
246+
* @return root
247+
*/
248+
public Node<T, V> root() {
249+
return root;
250+
}
251+
252+
/**
253+
* Inserts a key into the tree
254+
* @param key to be inserted
255+
*/
256+
public void insert(T key, V value) {
257+
if (root == null) {
258+
root = new Node<>(key, value);
259+
} else {
260+
insert(root, key, value);
261+
}
262+
}
263+
264+
/**
265+
* Removes a key from the tree, if it exists
266+
* @param key to be removed
267+
*/
268+
public void delete(T key) {
269+
root = delete(root, key);
270+
}
271+
272+
/**
273+
* Search for a node with the specified key.
274+
* @param key the key to look for
275+
* @return node that has the specified key; null if not found
276+
*/
277+
public Node<T, V> search(T key) {
278+
Node<T, V> curr = root;
279+
while (curr != null) {
280+
if (curr.key.compareTo(key) < 0) {
281+
curr = curr.right;
282+
} else if (curr.key.compareTo(key) > 0) {
283+
curr = curr.left;
284+
} else {
285+
return curr;
286+
}
287+
}
288+
return null;
289+
}
290+
291+
/**
292+
* Search for the predecessor of a given key.
293+
* @param key find predecessor of this key
294+
* @return generic type value; null if key has no predecessor
295+
*/
296+
public T predecessor(T key) {
297+
Node<T, V> curr = root;
298+
while (curr != null) {
299+
if (curr.key.compareTo(key) == 0) {
300+
break;
301+
} else if (curr.key.compareTo(key) < 0) {
302+
curr = curr.right;
303+
} else {
304+
curr = curr.left;
305+
}
306+
}
307+
308+
return predecessor(curr); // pred could be an ancestor or child of curr node and hence handled separately
309+
}
310+
311+
/**
312+
* Search for the successor of a given key.
313+
* @param key find successor of this key
314+
* @return generic type value; null if key has no successor
315+
*/
316+
public T successor(T key) {
317+
Node<T, V> curr = root;
318+
while (curr != null) {
319+
if (curr.key.compareTo(key) == 0) {
320+
break;
321+
} else if (curr.key.compareTo(key) < 0) {
322+
curr = curr.right;
323+
} else {
324+
curr = curr.left;
325+
}
326+
}
327+
328+
return successor(curr); // same exp as in the pred fn
329+
}
330+
331+
/**
332+
* prints in order traversal of the entire tree.
333+
*/
334+
public void printInorder() {
335+
System.out.print("In-order: ");
336+
printInorder(root);
337+
System.out.println();
338+
}
339+
340+
/**
341+
* prints pre-order traversal of the entire tree
342+
*/
343+
public void printPreorder() {
344+
System.out.print("Pre-order: ");
345+
printPreorder(root);
346+
System.out.println();
347+
}
348+
349+
/**
350+
* prints post-order traversal of the entire tree
351+
*/
352+
public void printPostorder() {
353+
System.out.print("Post-order: ");
354+
printPostorder(root);
355+
System.out.println();
356+
}
357+
358+
/**
359+
* prints level-order traversal of the entire tree
360+
*/
361+
public void printLevelorder() {
362+
System.out.print("Level-order: ");
363+
printLevelorder(root);
364+
System.out.println();
365+
}
366+
}

0 commit comments

Comments
 (0)