diff --git a/operations_on_datastructures/inorder_successor_of_bst.cpp b/operations_on_datastructures/inorder_successor_of_bst.cpp new file mode 100644 index 000000000..07e53c61b --- /dev/null +++ b/operations_on_datastructures/inorder_successor_of_bst.cpp @@ -0,0 +1,345 @@ +/** + * @file + * @brief An implementation for finding [Inorder successor of binary search tree](link) + * 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. + * + * ### Case 1 : The given node has 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 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 to the parent, 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. + * + * @author [Nitin Sharma](https://github.com/foo290) + * */ + + +#include /// For IO Operations +#include /// For std::vector +#include /// For assert + +namespace binary_search_tree { +/** + * @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; + } + else if (data > root->data) { + /// recursive call + return getNode(root->right, data); + } + else { + /// recursive call + 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 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. + * + * @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) { + // O(h) + + 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) { + + if (current->data < ancestor->data) { + // This means my current node is in left of the root node + successor = ancestor; + ancestor = ancestor->left; // keep going left + } else { + ancestor = ancestor->right; + } + } + return successor; // Nodes with maximum vales will not have a successor + } + } + + /** + * @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 &data) { + for (int64_t values: data) { + root = Insert(root, values); + } + return root; + } + } // namespace binary_search_tree + +/** + * @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 + 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 binary_search_tree::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."); + + binary_search_tree::Node *root = nullptr; + std::vector node_data {20, 3, 5, 6, 2, 23, 45 , 78, 21}; ///< Data to make nodes in BST + + root = binary_search_tree::makeBST(root, node_data); ///< Adding nodes to BST + + std::cout<<"Inorder sequence is : "; + binary_search_tree::printInorder(root); ///< Printing inorder to cross-verify. + std::cout< node_data {20, 3, 5, 6, 2, 23, 45 , 78, 21}; ///< Data to make nodes in BST + + root = binary_search_tree::makeBST(root, node_data); ///< Adding nodes to BST + + std::cout<<"Inorder sequence is : "; + binary_search_tree::printInorder(root); ///< Printing inorder to cross-verify. + std::cout<data == expectedOutput); + log("Assertion check passed!"); + + 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 : "); + + binary_search_tree::Node *root = nullptr; + std::vector node_data {89, 67, 32, 56, 90, 123, 120, 110, 115, 6, 78, 7, 10}; ///< Data to make nodes in BST + + root = binary_search_tree::makeBST(root, node_data); ///< Adding nodes to BST + + std::cout<<"Inorder sequence is : "; + binary_search_tree::printInorder(root); ///< Printing inorder to cross-verify. + std::cout<data == expectedOutput); + log("Assertion check passed!"); + + 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 + + binary_search_tree::Node *root = nullptr; ///< root node of the bst + std::vector 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 = binary_search_tree::makeBST(root, node_data); ///< Making BST + + binary_search_tree::Node *inorderSuccessor = + binary_search_tree::getInorderSuccessor(root, targetElement); + + std::cout<<"In-order sequence is : "; + binary_search_tree::printInorder(root); + std::cout<data; + } + + return 0; +} \ No newline at end of file