-
Notifications
You must be signed in to change notification settings - Fork 14
/
Copy pathbst.cpp
302 lines (266 loc) · 11.1 KB
/
bst.cpp
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
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
#include "bst.h"
using namespace std;
// Creating binary Tree
BinaryTree* create_tree() {
BinaryTree* bt = (BinaryTree *)malloc(sizeof(BinaryTree));
if(bt != nullptr) {
*bt = nullptr;
}
return bt;
}
// Deleting nodes
void delete_node(Node *no) {
if(no != nullptr) {
delete_node(no->left);
delete_node(no->right);
free(no);
no = nullptr;
}
}
// Deleting Tree
void delete_tree(BinaryTree *bt) {
if(bt != nullptr) {
delete_node(*bt);
free(bt);
bt = nullptr;
}
}
// Accessing tree informations
int isEmpty(BinaryTree *bt) {
if(bt == nullptr || *bt == nullptr)
return true;
return false;
}
int nodeNumber(BinaryTree *bt) {
if(bt == nullptr || *bt == nullptr)
return 0;
int height_left = nodeNumber(&((*bt)->left));
int height_right = nodeNumber(&((*bt)->right));
return (height_left + height_right + 1);
}
int tree_height(BinaryTree *bt) {
if(bt == nullptr || *bt == nullptr)
return 0;
int height_left = tree_height(&((*bt)->left));
int height_right = tree_height(&((*bt)->right));
if(height_left > height_right)
return (height_left + 1);
else
return (height_right + 1);
}
// Transversing tree: pre-order: root, left children, right children
void pre_order(BinaryTree *bt) {
if(bt != nullptr && *bt != nullptr) {
cout << (*bt)->number << " ";
pre_order(&((*bt)->left));
pre_order(&((*bt)->right));
}
}
// Transversing tree: in-order: left, root, right
void in_order(BinaryTree *bt) {
if(bt != nullptr && *bt != nullptr) {
in_order(&((*bt)->left));
cout << (*bt)->number << " ";
in_order(&((*bt)->right));
}
}
// Transversing tree: post-order: left, right, root
void post_order(BinaryTree *bt) {
if(bt != nullptr && *bt != nullptr) {
post_order(&((*bt)->left));
post_order(&((*bt)->right));
cout << (*bt)->number << " ";
}
}
// Insertion in a Binary search tree
/*
To insert a value in a binary search tree:
first compare the value with the root,
if v is lesser than the root
go to the subtree at the left
else
go to subtree at the right
apply the method recursively (but it can be done without recursion)
*/
int insert_value(BinaryTree *bt, int number) {
if(bt == nullptr)
return 0; // Error, the tree doesn't exist
Node *no = (Node *)malloc(sizeof(Node));
if(no == nullptr)
return 0; // Error, when tried to allocate memory for the node
no->number = number;
no->left = no->right = nullptr;
// Search where insert it
if(*bt == nullptr) // If the tree is empty
*bt = no; // First node of the tree
else {
Node *current = *bt;
Node *previous = nullptr;
while(current != nullptr) { // While the current value is different of null, that is, while it hasn't found an empty place to insert the value
previous = current; // Previous receives the current value, since bellow current is going to change its value to either left or right node
if(number == current->number) { // If the number passed already exist in the tree, then it will not be inserted, since the tree does not allow repeated numbers
free(no);
return 0; // Error, number already exist
}
if(number > current->number) { // If the number is greater than the number in the current node, then it must go to the right of it
current = current->right;
} else {
current = current->left; // Otherwise, it goes to the left
}
}
// When the current has achieved the null value, it has got into a empty place to insert the value then:
// previous stores the node previous to the current, previous is a leaf node
if (previous->number < number) // The number must be inserted in the right
previous->right = no;
else
previous->left = no;
}
return 1; // Everything went okay
}
// That function is responsible to treat all possible configurations of deletion
// when the node has no child, only one child and two children
Node* remove_current(Node *current) {
Node *nodeLeft, *nodeRight;
// without any child
if(current->left == nullptr && current->right == nullptr) {
// deallocating memory
free(current);
// avoid dangling pointer
current = nullptr;
// return null to the previous node that was pointing to the removed node
return nullptr;
}
// Without a child at the left but with one at the right
if(current->left == nullptr) {
// making the previous node pointing to whatever child the current node was pointing to
// since it has only one child, and in this case at the right.
nodeRight = current->right;
// deallocating memory
free(current);
// avoid dangling pointer
current = nullptr;
// return the right child to the previous one
return nodeRight;
}
// in case there's only one child, but now at the left
if(current->right == nullptr) {
// making the previous node pointing to whatever child the current node was pointing to
// since it has only one child, and in this case at the left.
nodeLeft = current->left;
// deallocating memory
free(current);
// avoid dangling pointer
current = nullptr;
// return the left child to the previous one
return nodeLeft;
}
// If it has gotten here, it means that the node to be deleted has two children
// so now it's time to search for a child at the rightmost side of the left subtree
// to overwrite the node to be deleted. that guarantees that the node taken from the
// rightmost side is lesser then the right child of the current node and this node is greater than the
// left child of the current node.
Node* previous = current;
// left subtree
nodeRight = current->left;
// Search for a child at the rightmost side of the subtree at the left
// while the nodeLeft is different of null, we haven't got to the rightmost child yet
while(nodeRight->right != nullptr) {
previous = nodeRight;
// moving to the right child
nodeRight = nodeRight->right;
}
// when node nodeRight->right is null, it means the rightMost child was found
// So now we can use the previous node that points to the right most child to point
// to whatever the right most child was pointing to, in case it has a left child
// and make the rightNode pointing to as its left child to the left child of the current node.
// Replace the removed node with the rightmost child in the left subtree
if(previous != current) {
// if it get here, it means that it was found a rightmost node, otherwise, the
// left child of current hasn't any right most child, which means that it must
// be swapped with the current node. (that's going to be the node that is going to pointing
// to whatever current was pointing to. i.e. it will be pointing to the right child of the removed node.
// in case the rightmost child has a left child
previous->right = nodeRight->left;
// making the rightmost child point to the left child of current
nodeRight->left = current->left;
}
// node right points to the right child of current one
nodeRight->right = current->right;
free(current);
// avoiding dangling pointer
current = nullptr;
// returning rightmost child for the previous node from the removed one point to it
return nodeRight;
}
/*
When the node has no child, we can simply make its parent node (previous) point to null
When the node has only one child (either left or right), make the previous node to it point to the child it was pointing
When the node has two children, to guarantee that after the deletion of a node, the binary search tree keep following the rules of a BST
we need to take the a child from the left subtree that is a most-right node and replace where the node is going to be deleted.
so that it's guarantee that this node is greater than the left child and smaller than the right child.
*/
// Delete a value in 3 situations: leaf node, one child and two children
int delete_value(BinaryTree *bt, int number) {
if(bt == nullptr)
return 0; // Error, binary tree doesn't exist
// Pointers to keep track of the previous one to the node
Node *current = *bt;
Node *previous = nullptr;
while(current != nullptr) {
// If the number was found, do the remotion of the value
if(number == current->number) {
// If the number is the root (check if root has one, two or none child)
if(current == *bt) {
*bt = remove_current(current);
} else {
// otherwise, if it's not the root, then
// checking if the element is at the right or left
// The node is at the right side
if(previous->right == current) {
// so the right node that previous was pointing to must be updated to either null, the only child the
// node to be deleted was pointing to, or the right-most child from the left subtree
previous->right = remove_current(current);
} else {
// If it's not the right, do the same for the left
// The node is at the left side
previous->left = remove_current(current);
}
}
// return 1, to specify that the element was removed
return 1;
}
// If the node wasn't found yet, keeping searching for value
previous = current; // Previous receives the current one, since bellow it's going to change
if(number > current->number) // If the number is greater than the number at the current node, then, it's supposed to be at the right
current = current->right;
else
current = current->left; // Otherwise, it's at the left subtree
}
return 0;
}
bool searchElementUtil(Node *node, int v) {
// if node is equal to null it means that the value wasn't found
if(node == nullptr)
return false;
// otherwise, check if number is equal to the current node
if(node->number == v) {
// return true in this case
return true;
} else {
// otherwise, check if the number might be in the right side or left
if(v < node->number) {
// might be at the left since its smaller than the number at the current node
return searchElementUtil(node->left, v);
} else {
// otherwise, it might be at the right
return searchElementUtil(node->right, v);
}
}
}
bool searchElement(BinaryTree* bt, int v) {
// if binary doesn't exists or is empty
if(bt == nullptr || *bt == nullptr)
return false;
// otherwise search for an element, it can be either recursive or not
return searchElementUtil(*bt, v);
}