Skip to content

Commit a527532

Browse files
committed
feat: add inorder successor in bst
1 parent 394811e commit a527532

File tree

1 file changed

+345
-0
lines changed

1 file changed

+345
-0
lines changed
Lines changed: 345 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,345 @@
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

Comments
 (0)