-
-
Notifications
You must be signed in to change notification settings - Fork 7.3k
/
inorder_successor_of_bst.cpp
429 lines (373 loc) · 14.4 KB
/
inorder_successor_of_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
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
/**
* @file
* @brief An implementation for finding the [Inorder successor of a binary
* search tree](https://www.youtube.com/watch?v=5cPbNCrdotA) Inorder
* successor of a node is the next node in Inorder traversal of the Binary Tree.
* Inorder Successor is NULL for the last node in Inorder traversal.
* @details
* ### Case 1: The given node has the right node/subtree
*
* * In this case, the left-most deepest node in the right subtree will
* come just after the given node as we go to left deep in inorder.
* - Go deep to left most node in right subtree.
* OR, we can also say in case if BST, find the minimum of the subtree
* for a given node.
*
* ### Case 2: The given node does not have a right node/subtree
*
* #### Method 1: Use parent pointer (store the address of parent nodes)
* * If a node does not have the right subtree, and we already visited the
* node itself, then the next node will be its parent node according to inorder
* traversal, and if we are going to parent from left, then the parent would be
* unvisited.
* * In other words, go to the nearest ancestor for which given node would
* be in left subtree.
*
* #### Method 2: Search from the root node
* * In case if there is no link from a child node to the parent node, we
* need to walk down the tree starting from the root node to the given node, by
* doing so, we are visiting every ancestor of the given node.
* * In order successor would be the deepest node in this path for which
* given node is in left subtree.
*
* @author [Nitin Sharma](https://github.com/foo290)
* */
#include <cassert> /// for assert
#include <iostream> /// for IO Operations
#include <vector> /// for std::vector
/**
* @namespace operations_on_datastructures
* @brief Operations on data structures
*/
namespace operations_on_datastructures {
/**
* @namespace inorder_successor_of_bst
* @brief Functions for the [Inorder successor of a binary search
* tree](https://www.youtube.com/watch?v=5cPbNCrdotA) implementation
*/
namespace inorder_traversal_of_bst {
/**
* @brief A Node structure representing a single node in BST
*/
class Node {
public:
int64_t data; ///< The key/value of the node
Node *left; ///< Pointer to Left child
Node *right; ///< Pointer to right child
};
/**
* @brief Allocates a new node in heap for given data and returns it's pointer.
* @param data Data for the node.
* @returns A pointer to the newly allocated Node.
* */
Node *makeNode(int64_t data) {
Node *node = new Node();
node->data = data; ///< setting data for node
node->left = nullptr; ///< setting left child as null
node->right = nullptr; ///< setting right child as null
return node;
}
/**
* @brief Inserts the given data in BST while maintaining the properties of BST.
* @param root Pointer to the root node of the BST
* @param data Data to be inserted.
* @returns Node* Pointer to the root node.
* */
Node *Insert(Node *root, int64_t data) {
if (root == nullptr) {
root = makeNode(data);
} else if (data <= root->data) {
root->left = Insert(root->left, data);
} else {
root->right = Insert(root->right, data);
}
return root;
}
/**
* @brief Searches the given data in BST and returns the pointer to the node
* containing that data.
* @param root Pointer to the root node of the BST
* @param data Data to be Searched.
* @returns Node* pointer to the found node
* */
Node *getNode(Node *root, int64_t data) {
if (root == nullptr) {
return nullptr;
} else if (root->data == data) {
return root; /// Node found!
} else if (data > root->data) {
/// Traverse right subtree recursively as the given data is greater than
/// the data in root node, data must be present in right subtree.
return getNode(root->right, data);
} else {
/// Traverse left subtree recursively as the given data is less than the
/// data in root node, data must be present in left subtree.
return getNode(root->left, data);
}
}
/**
* @brief Finds and return the minimum node in BST.
* @param root A pointer to root node.
* @returns Node* Pointer to the found node
* */
Node *findMinNode(Node *root) {
if (root == nullptr) {
return root;
}
while (root->left != nullptr) {
root = root->left;
}
return root;
}
/**
* @brief Prints the BST in inorder traversal using recursion.
* @param root A pointer to the root node of the BST.
* @returns void
* */
void printInorder(Node *root) {
if (root == nullptr) {
return;
}
printInorder(root->left); /// recursive call to left subtree
std::cout << root->data << " ";
printInorder(root->right); /// recursive call to right subtree
}
/**
* @brief This function is used in test cases to quickly create BST containing
* large data instead of hard coding it in code. For a given root, this will add
* all the nodes containing data passes in data vector.
* @param root Pointer to the root node.
* @param data A vector containing integer values which are suppose to be
* inserted as nodes in BST.
* @returns Node pointer to the root node.
* */
Node *makeBST(Node *root, const std::vector<int64_t> &data) {
for (int64_t values : data) {
root = Insert(root, values);
}
return root;
}
/**
* @brief Inorder successor of a node is the next node in inorder traversal of
* the Binary Tree. This function takes the root node and the data of the node
* for which we have to find the inorder successor, and returns the inorder
* successor node.
* @details Search from the root node as we need to walk the tree starting from
* the root node to the given node, by doing so, we are visiting every ancestor
* of the given node. In order successor would be the deepest node in this path
* for which given node is in left subtree. Time complexity O(h)
* @param root A pointer to the root node of the BST
* @param data The data (or the data of node) for which we have to find inorder
* successor.
* @returns Node pointer to the inorder successor node.
* */
Node *getInorderSuccessor(Node *root, int64_t data) {
Node *current = getNode(root, data);
if (current == nullptr) {
return nullptr;
}
// Case - 1
if (current->right != nullptr) {
return findMinNode(current->right);
}
// case - 2
else {
Node *successor = nullptr;
Node *ancestor = root;
while (ancestor != current && ancestor != nullptr) {
// This means my current node is in left of the root node
if (current->data < ancestor->data) {
successor = ancestor;
ancestor = ancestor->left; // keep going left
} else {
ancestor = ancestor->right;
}
}
return successor; // Nodes with maximum vales will not have a successor
}
}
/**
* @brief This function clears the memory allocated to entire tree recursively.
* Its just for clean up the memory and not relevant to the actual topic.
* @param root Root node of the tree.
* @returns void
* */
void deallocate(Node *rootNode) {
if (rootNode == nullptr) {
return;
}
deallocate(rootNode->left);
deallocate(rootNode->right);
delete (rootNode);
}
} // namespace inorder_traversal_of_bst
} // namespace operations_on_datastructures
/**
* @brief class encapsulating the necessary test cases
*/
class TestCases {
private:
/**
* @brief A function to print given message on console.
* @tparam T Type of the given message.
* @returns void
* */
template <typename T>
void log(T msg) {
// It's just to avoid writing cout and endl
std::cout << "[TESTS] : ---> " << msg << std::endl;
}
public:
/**
* @brief Executes test cases
* @returns void
* */
void runTests() {
log("Running Tests...");
testCase_1();
testCase_2();
testCase_3();
log("Test Cases over!");
std::cout << std::endl;
}
/**
* @brief A test case contains edge case, printing inorder successor of last
* node.
* @returns void
* */
void testCase_1() {
const operations_on_datastructures::inorder_traversal_of_bst::Node
*expectedOutput = nullptr; ///< Expected output of this test
log("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
log("This is test case 1 : ");
log("Description:");
log(" EDGE CASE : Printing inorder successor for last node in the "
"BST, Output will be nullptr.");
operations_on_datastructures::inorder_traversal_of_bst::Node *root =
nullptr;
std::vector<int64_t> node_data{
20, 3, 5, 6, 2, 23, 45, 78, 21}; ///< Data to make nodes in BST
root = operations_on_datastructures::inorder_traversal_of_bst::makeBST(
root,
node_data); ///< Adding nodes to BST
std::cout << "Inorder sequence is : ";
operations_on_datastructures::inorder_traversal_of_bst::printInorder(
root); ///< Printing inorder to cross-verify.
std::cout << std::endl;
operations_on_datastructures::inorder_traversal_of_bst::Node
*inorderSuccessor = operations_on_datastructures::
inorder_traversal_of_bst::getInorderSuccessor(
root, 78); ///< The inorder successor node for given data
log("Checking assert expression...");
assert(inorderSuccessor == expectedOutput);
log("Assertion check passed!");
operations_on_datastructures::inorder_traversal_of_bst::deallocate(
root); /// memory cleanup!
log("[PASS] : TEST CASE 1 PASS!");
log("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
}
/**
* @brief A test case which contains main list of 100 elements and sublist
* of 20.
* @returns void
* */
void testCase_2() {
const int expectedOutput = 21; ///< Expected output of this test
log("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
log("This is test case 2 : ");
operations_on_datastructures::inorder_traversal_of_bst::Node *root =
nullptr;
std::vector<int64_t> node_data{
20, 3, 5, 6, 2, 23, 45, 78, 21}; ///< Data to make nodes in BST
root = operations_on_datastructures::inorder_traversal_of_bst::makeBST(
root,
node_data); ///< Adding nodes to BST
std::cout << "Inorder sequence is : ";
operations_on_datastructures::inorder_traversal_of_bst::printInorder(
root); ///< Printing inorder to cross-verify.
std::cout << std::endl;
operations_on_datastructures::inorder_traversal_of_bst::Node
*inorderSuccessor = operations_on_datastructures::
inorder_traversal_of_bst::getInorderSuccessor(
root, 20); ///< The inorder successor node for given data
log("Checking assert expression...");
assert(inorderSuccessor->data == expectedOutput);
log("Assertion check passed!");
operations_on_datastructures::inorder_traversal_of_bst::deallocate(
root); /// memory cleanup!
log("[PASS] : TEST CASE 2 PASS!");
log("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
}
/**
* @brief A test case which contains main list of 50 elements and sublist
* of 20.
* @returns void
* */
void testCase_3() {
const int expectedOutput = 110; ///< Expected output of this test
log("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
log("This is test case 3 : ");
operations_on_datastructures::inorder_traversal_of_bst::Node *root =
nullptr;
std::vector<int64_t> node_data{
89, 67, 32, 56, 90, 123, 120,
110, 115, 6, 78, 7, 10}; ///< Data to make nodes in BST
root = operations_on_datastructures::inorder_traversal_of_bst::makeBST(
root,
node_data); ///< Adding nodes to BST
std::cout << "Inorder sequence is : ";
operations_on_datastructures::inorder_traversal_of_bst::printInorder(
root); ///< Printing inorder to cross-verify.
std::cout << std::endl;
operations_on_datastructures::inorder_traversal_of_bst::Node
*inorderSuccessor = operations_on_datastructures::
inorder_traversal_of_bst::getInorderSuccessor(
root, 90); ///< The inorder successor node for given data
log("Checking assert expression...");
assert(inorderSuccessor->data == expectedOutput);
log("Assertion check passed!");
operations_on_datastructures::inorder_traversal_of_bst::deallocate(
root); /// memory cleanup!
log("[PASS] : TEST CASE 3 PASS!");
log("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
}
};
/**
* @brief Self-test implementations
* @returns void
*/
static void test() {
TestCases tc;
tc.runTests();
}
/**
* @brief Main function
* @param argc commandline argument count (ignored)
* @param argv commandline array of arguments (ignored)
* @returns 0 on exit
*/
int main(int argc, char *argv[]) {
test(); // run self-test implementations
operations_on_datastructures::inorder_traversal_of_bst::Node *root =
nullptr; ///< root node of the bst
std::vector<int64_t> node_data{3, 4, 5,
89, 1, 2}; ///< Data to add nodes in BST
int64_t targetElement = 4; ///< An element to find inorder successor for.
root = operations_on_datastructures::inorder_traversal_of_bst::makeBST(
root, node_data); ///< Making BST
operations_on_datastructures::inorder_traversal_of_bst::Node
*inorderSuccessor = operations_on_datastructures::
inorder_traversal_of_bst::getInorderSuccessor(root, targetElement);
std::cout << "In-order sequence is : ";
operations_on_datastructures::inorder_traversal_of_bst::printInorder(root);
std::cout << std::endl;
if (inorderSuccessor == nullptr) {
std::cout << "Inorder successor for last node is NULL" << std::endl;
} else {
std::cout << "Target element is : " << targetElement << std::endl;
std::cout << "Inorder successor for target element is : "
<< inorderSuccessor->data << std::endl;
}
deallocate(root); /// memory cleanup!
return 0;
}