-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathBinarySearchTree.java
210 lines (189 loc) · 6.76 KB
/
BinarySearchTree.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
package nonlinear;
public class BinarySearchTree extends BinaryTree {
Node root;
public BinarySearchTree(Node root) {
super(root);
}
// All Traversals in DFS and BFS extends from super class BinaryTree and available in this class
/**
* Searches for a given value in the BinarySearchTree by using the BST property - root is greater than left and less than right
*
* @param value to be searched in Tree
* @return Node which matches the given value Or null if Tree is null or not found.
* Time Complexity - O(h) , O(logn) if we maintain a Balanced Search Tree for every insert and delete like AVL and Red Black Trees
*/
public Node search(int value) {
if (this.root == null) return null;
return findIterative(value, root);
}
// Recursive find - Space Complexity - O(h)
private Node find(int value, Node node) {
if (node == null) return null;
if (node.data == value) return node;
if (node.data > value) {
//search left
return find(value, node.left);
} else {
//search right
return find(value, node.right);
}
}
// Iterative find - Space Complexity - O(1)
private Node findIterative(int value, Node node) {
if (node == null) return null;
while(node != null){
if(node.data == value) return node;
if(node.data < value){
node = node.right;
}else{
node = node.left;
}
}
return null;
}
/**
* Method to calculate the height of the Tree
*
* @return current height of the tree
*/
public int getHeight() {
return maxHeight(root);
}
private int maxHeight(Node node) {
if (node == null) return 0;
return 1 + Math.max(maxHeight(node.left), maxHeight(node.right));
}
/**
* Method to calculate the minimum value present in the Tree
*
* @return current minimum of the tree
* Time Complexity - O(h) where h is the height of the BinaryTree
*/
public int getMin() {
if (root == null) return -1;
Node currNode = root;
Node leftNode = root.left;
while (leftNode != null) {
currNode = leftNode;
leftNode = leftNode.left;
}
return currNode.data;
}
/**
* Method to calculate the maximum value present in the Tree
*
* @return current maximum of the tree
* Time Complexity - O(h) where h is the height of the BinaryTree
*/
public int getMax() {
if (root == null) return -1;
Node currNode = root;
Node rightNode = root.right;
while (rightNode != null) {
currNode = rightNode;
rightNode = rightNode.right;
}
return currNode.data;
}
/**
* Inserts a new node with given value at the correct place in the BinarySearchTree. Uses Binary Search.
* Time Complexity - O(h), O(log n) if we maintain a Balanced Search Tree for every insert and delete like AVL and Red Black Trees
* Space Complexity - O(h)
* @param value
*/
public void insert(int value) {
Node node = new Node(value);
if (root == null) {
this.root = node;
return;
}
Node parent = findParentForInsert(value, root);
if (parent != null) { // This should never be null for non-empty tree which is already checked above
if (parent.data < value) {
parent.right = node;
} else if (parent.data > value) {
parent.left = node;
}
// Ignore duplicate if already exists
}
}
/**
* Inserts a new node with given value at the correct place in the BinarySearchTree Iteratively. Uses Binary Search.
* Time Complexity - O(h), O(log n) if we maintain a Balanced Search Tree for every insert and delete like AVL and Red Black Trees
* Space Complexity - O(1)
*
* @param value
*/
public void insertIterative(int value){
Node newNode = new Node(value);
if (root == null){
this.root = newNode;
return;
}
Node parent = null;
Node current = root;
while(current != null){
parent = current;
if(current.data == value) return; // Ignore if Node with value already exists
if(current.data < value){
current = current.right;
}else{
current = current.left;
}
}
if(parent.data < value){
parent.right = newNode;
}else{
parent.left = newNode;
}
}
private Node findParentForInsert(int value, Node node) {
if (node == null) return null;
if (node.data >= value) {
//search left
Node parentNode = findParentForInsert(value, node.left);
if (parentNode == null) return node; // No left
} else {
//search right
Node parentNode = findParentForInsert(value, node.right);
if (parentNode == null) return node; // No right
}
return null;
}
/**
* Deletes a node with given value.
*
* @param value
*/
public void delete(int value) {
/**
Deleting a node in a BST can be one of the more complex operations, mainly because it needs to account for different scenarios while maintaining the BST properties. Here are the common scenarios we need to handle:
Node with No Children (Leaf Node): Simply remove the node.
Node with One Child: Replace the node with its child.
Node with Two Children: Find the node's in-order successor (the smallest node in its right subtree) or in-order predecessor (the largest node in its left subtree), copy its value to the node, and then delete the in-order successor or predecessor.
*/
delNode(root, value);
}
private Node delNode(Node root, int value){
if(root == null) return null;
if(root.data < value){
root.right = delNode(root.right, value);
}else if(root.data > value){
root.left = delNode(root.left, value);
} else {
if(root.right == null) return root.left;
if(root.left == null) return root.right;
Node succesorNode = getInOderSuccessorForDelete(root);
delNode(succesorNode,value); // deletes the successor node as this is moved to current root
root.data = succesorNode.data;
}
return root;
}
private Node getInOderSuccessorForDelete(Node root){
Node curr = root.right;
while(curr != null && curr.left != null){
curr = curr.left;
}
return curr;
}
}