1
+ /* *
2
+ * @file
3
+ * @brief An implementation for finding [Inorder successor of binary search tree](link)
4
+ * 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.
5
+ *
6
+ * ### Case 1 : The given node has right node/subtree
7
+ * In this case the left most deepest node in the right subtree will come just after the given node as we go to left
8
+ * deep in inorder.
9
+ * - Go deep to left most node in right subtree.
10
+ * OR, we can also say in case if BST, find the minimum of the subtree for a given node.
11
+ *
12
+ * ### Case 2 : The given node does not have a right node/subtree
13
+ *
14
+ * #### Method 1 : Use parent pointer (store the address of parent nodes)
15
+ * If a node does not have right subtree, and we already visited the node itself,
16
+ * then the next node will be its parent node according to inorder traversal, and if we are going to parent from left,
17
+ * then the parent would be unvisited. In other words, go to the nearest ancestor for which given node would be in left subtree.
18
+ *
19
+ * #### Method 2 : Search from the root node
20
+ * In case if there is no link to the parent, we need to walk the tree starting from the root node to the given node,
21
+ * by doing so, we are visiting every ancestor of the given node. In order successor would be the deepest node in
22
+ * this path for which given node is in left subtree.
23
+ *
24
+ * @author [Nitin Sharma](https://github.com/foo290)
25
+ * */
26
+
27
+
28
+ #include < iostream> // / For IO Operations
29
+ #include < vector> // / For std::vector
30
+ #include < cassert> // / For assert
31
+
32
+ namespace binary_search_tree {
33
+ /* *
34
+ * @brief A Node structure representing a single node in bst.
35
+ */
36
+ class Node {
37
+ public:
38
+ int64_t data; // /< The key/value of the node
39
+ Node *left; // /< Pointer to Left child
40
+ Node *right; // /< Pointer to right child
41
+ };
42
+
43
+ /* *
44
+ * @brief Allocates a new node in heap for given data and returns it's pointer.
45
+ * @param data Data for the node.
46
+ * @returns A pointer to the newly allocated Node.
47
+ * */
48
+ Node *makeNode (int64_t data) {
49
+ Node *node = new Node ();
50
+ node->data = data; // /< setting data for node
51
+ node->left = nullptr ; // /< setting left child as null
52
+ node->right = nullptr ; // /< setting right child as null
53
+ return node;
54
+ }
55
+
56
+ /* *
57
+ * @brief Inserts the given data in BST while maintaining the properties of BST.
58
+ * @param root Pointer to the root node of the BST
59
+ * @param data Data to be inserted.
60
+ * @returns Node* Pointer to the root node.
61
+ * */
62
+ Node *Insert (Node *root, int64_t data) {
63
+ if (root == nullptr ) {
64
+ root = makeNode (data);
65
+ } else if (data <= root->data ) {
66
+ root->left = Insert (root->left , data);
67
+ } else {
68
+ root->right = Insert (root->right , data);
69
+ }
70
+ return root;
71
+ }
72
+
73
+ /* *
74
+ * @brief Searches the given data in BST and returns the pointer to the node containing that data.
75
+ * @param root Pointer to the root node of the BST
76
+ * @param data Data to be Searched.
77
+ * @returns Node* pointer to the found node
78
+ * */
79
+ Node *getNode (Node *root, int64_t data) {
80
+ if (root == nullptr ) {
81
+ return nullptr ;
82
+ }
83
+ else if (root->data == data) {
84
+ return root;
85
+ }
86
+ else if (data > root->data ) {
87
+ // / recursive call
88
+ return getNode (root->right , data);
89
+ }
90
+ else {
91
+ // / recursive call
92
+ return getNode (root->left , data);
93
+ }
94
+ }
95
+
96
+ /* *
97
+ * @brief Finds and return the minimum node in BST.
98
+ * @param root A pointer to root node.
99
+ * @returns Node* Pointer to the found node
100
+ * */
101
+ Node *findMinNode (Node *root) {
102
+ if (root == nullptr ) {
103
+ return root;
104
+ }
105
+ while (root->left != nullptr ) {
106
+ root = root->left ;
107
+ }
108
+ return root;
109
+ }
110
+
111
+ /* *
112
+ * @brief Search from the root node as we need to walk the tree starting from the root node to the given node,
113
+ * by doing so, we are visiting every ancestor of the given node.
114
+ * In order successor would be the deepest node in this path for which given node is in left subtree.
115
+ *
116
+ * @param root A pointer to the root node of the BST
117
+ * @param data The data (or the data of node) for which we have to find inorder successor.
118
+ * @returns Node pointer to the inorder successor node.
119
+ * */
120
+ Node *getInorderSuccessor (Node *root, int64_t data) {
121
+ // O(h)
122
+
123
+ Node *current = getNode (root, data);
124
+ if (current == nullptr ) return nullptr ;
125
+
126
+ // Case - 1
127
+ if (current->right != nullptr ) {
128
+ return findMinNode (current->right );
129
+ }
130
+ // case - 2
131
+ else {
132
+ Node *successor = nullptr ;
133
+ Node *ancestor = root;
134
+
135
+ while (ancestor != current) {
136
+
137
+ if (current->data < ancestor->data ) {
138
+ // This means my current node is in left of the root node
139
+ successor = ancestor;
140
+ ancestor = ancestor->left ; // keep going left
141
+ } else {
142
+ ancestor = ancestor->right ;
143
+ }
144
+ }
145
+ return successor; // Nodes with maximum vales will not have a successor
146
+ }
147
+ }
148
+
149
+ /* *
150
+ * @brief Prints the BST in inorder traversal using recursion.
151
+ * @param root A pointer to the root node of the BST.
152
+ * @returns void
153
+ * */
154
+ void printInorder (Node *root) {
155
+ if (root == nullptr ) return ;
156
+
157
+ printInorder (root->left ); // / recursive call to left subtree
158
+ std::cout << root->data << " " ;
159
+ printInorder (root->right ); // / recursive call to right subtree
160
+
161
+ }
162
+
163
+ /* *
164
+ * @brief This function is used in test cases to quickly create BST containing large data instead of hard coding it in code.
165
+ * For a given root, this will add all the nodes containing data passes in data vector.
166
+ * @param root Pointer to the root node.
167
+ * @param data A vector containing integer values which are suppose to be inserted as nodes in BST.
168
+ * @returns Node pointer to the root node.
169
+ * */
170
+ Node *makeBST (Node *root, const std::vector<int64_t > &data) {
171
+ for (int64_t values: data) {
172
+ root = Insert (root, values);
173
+ }
174
+ return root;
175
+ }
176
+ } // namespace binary_search_tree
177
+
178
+ /* *
179
+ * @brief class encapsulating the necessary test cases
180
+ */
181
+ class TestCases {
182
+ private:
183
+ /* *
184
+ * @brief A function to print given message on console.
185
+ * @tparam T Type of the given message.
186
+ * @returns void
187
+ * */
188
+ template <typename T>
189
+ void log (T msg) {
190
+ // It's just to avoid writing cout and endl
191
+ std::cout << " [TESTS] : ---> " << msg << std::endl;
192
+ }
193
+
194
+ public:
195
+ /* *
196
+ * @brief Executes test cases
197
+ * @returns void
198
+ * */
199
+ void runTests () {
200
+ log (" Running Tests..." );
201
+
202
+ testCase_1 ();
203
+ testCase_2 ();
204
+ testCase_3 ();
205
+
206
+ log (" Test Cases over!" );
207
+ std::cout << std::endl;
208
+ }
209
+
210
+ /* *
211
+ * @brief A test case contains edge case, printing inorder successor of last node.
212
+ * @returns void
213
+ * */
214
+ void testCase_1 () {
215
+ const binary_search_tree::Node *expectedOutput = nullptr ; // /< Expected output of this test
216
+
217
+ log (" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" );
218
+ log (" This is test case 1 : " );
219
+ log (" Description:" );
220
+ log (" EDGE CASE : Printing inorder successor for last node in the BST, Output will be nullptr." );
221
+
222
+ binary_search_tree::Node *root = nullptr ;
223
+ std::vector<int64_t > node_data {20 , 3 , 5 , 6 , 2 , 23 , 45 , 78 , 21 }; // /< Data to make nodes in BST
224
+
225
+ root = binary_search_tree::makeBST (root, node_data); // /< Adding nodes to BST
226
+
227
+ std::cout<<" Inorder sequence is : " ;
228
+ binary_search_tree::printInorder (root); // /< Printing inorder to cross-verify.
229
+ std::cout<<std::endl;
230
+
231
+ binary_search_tree::Node *inorderSuccessor =
232
+ binary_search_tree::getInorderSuccessor (root, 78 ); // /< The inorder successor node for given data
233
+
234
+ log (" Checking assert expression..." );
235
+ assert (inorderSuccessor == expectedOutput);
236
+ log (" Assertion check passed!" );
237
+
238
+ log (" [PASS] : TEST CASE 1 PASS!" );
239
+ log (" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" );
240
+ }
241
+
242
+ /* *
243
+ * @brief A test case which contains main list of 100 elements and sublist
244
+ * of 20.
245
+ * @returns void
246
+ * */
247
+ void testCase_2 () {
248
+ const int expectedOutput = 21 ; // /< Expected output of this test
249
+
250
+ log (" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" );
251
+ log (" This is test case 2 : " );
252
+
253
+ binary_search_tree::Node *root = nullptr ;
254
+ std::vector<int64_t > node_data {20 , 3 , 5 , 6 , 2 , 23 , 45 , 78 , 21 }; // /< Data to make nodes in BST
255
+
256
+ root = binary_search_tree::makeBST (root, node_data); // /< Adding nodes to BST
257
+
258
+ std::cout<<" Inorder sequence is : " ;
259
+ binary_search_tree::printInorder (root); // /< Printing inorder to cross-verify.
260
+ std::cout<<std::endl;
261
+
262
+ binary_search_tree::Node *inorderSuccessor =
263
+ binary_search_tree::getInorderSuccessor (root, 20 ); // /< The inorder successor node for given data
264
+
265
+ log (" Checking assert expression..." );
266
+ assert (inorderSuccessor->data == expectedOutput);
267
+ log (" Assertion check passed!" );
268
+
269
+ log (" [PASS] : TEST CASE 2 PASS!" );
270
+ log (" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" );
271
+ }
272
+
273
+ /* *
274
+ * @brief A test case which contains main list of 50 elements and sublist
275
+ * of 20.
276
+ * @returns void
277
+ * */
278
+ void testCase_3 () {
279
+ const int expectedOutput = 110 ; // /< Expected output of this test
280
+
281
+ log (" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" );
282
+ log (" This is test case 3 : " );
283
+
284
+ binary_search_tree::Node *root = nullptr ;
285
+ 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
286
+
287
+ root = binary_search_tree::makeBST (root, node_data); // /< Adding nodes to BST
288
+
289
+ std::cout<<" Inorder sequence is : " ;
290
+ binary_search_tree::printInorder (root); // /< Printing inorder to cross-verify.
291
+ std::cout<<std::endl;
292
+
293
+ binary_search_tree::Node *inorderSuccessor =
294
+ binary_search_tree::getInorderSuccessor (root, 90 ); // /< The inorder successor node for given data
295
+
296
+ log (" Checking assert expression..." );
297
+ assert (inorderSuccessor->data == expectedOutput);
298
+ log (" Assertion check passed!" );
299
+
300
+ log (" [PASS] : TEST CASE 3 PASS!" );
301
+ log (" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" );
302
+ }
303
+ };
304
+
305
+ /* *
306
+ * @brief Self-test implementations
307
+ * @returns void
308
+ */
309
+ static void test () {
310
+ TestCases tc;
311
+ tc.runTests ();
312
+ }
313
+
314
+ /* *
315
+ * @brief Main function
316
+ * @param argc commandline argument count (ignored)
317
+ * @param argv commandline array of arguments (ignored)
318
+ * @returns 0 on exit
319
+ */
320
+ int main (int argc, char *argv[]) {
321
+ test (); // / run self-test implementations
322
+
323
+ binary_search_tree::Node *root = nullptr ; // /< root node of the bst
324
+ std::vector<int64_t > node_data{3 , 4 , 5 , 89 , 1 , 2 }; // /< Data to add nodes in BST
325
+
326
+ int64_t targetElement = 4 ; // /< An element to find inorder successor for.
327
+ root = binary_search_tree::makeBST (root, node_data); // /< Making BST
328
+
329
+ binary_search_tree::Node *inorderSuccessor =
330
+ binary_search_tree::getInorderSuccessor (root, targetElement);
331
+
332
+ std::cout<<" In-order sequence is : " ;
333
+ binary_search_tree::printInorder (root);
334
+ std::cout<<std::endl;
335
+
336
+ if (inorderSuccessor == nullptr ) {
337
+ std::cout<<" Inorder successor for last node is NULL" <<std::endl;
338
+ }
339
+ else {
340
+ std::cout<<" Target element is : " <<targetElement<<std::endl;
341
+ std::cout<<" Inorder successor for target element is : " <<inorderSuccessor->data ;
342
+ }
343
+
344
+ return 0 ;
345
+ }
0 commit comments