diff --git a/DIRECTORY.md b/DIRECTORY.md index 0d359fddb..7e75121d0 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -279,6 +279,7 @@ * [Pascal Triangle](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/others/pascal_triangle.cpp) * [Postfix Evaluation](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/others/postfix_evaluation.cpp) * [Primality Test](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/others/primality_test.cpp) + * [Recursive Tree Traversal](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/others/recursive_tree_traversal.cpp) * [Smallest Circle](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/others/smallest_circle.cpp) * [Sparse Matrix](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/others/sparse_matrix.cpp) * [Spiral Print](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/others/spiral_print.cpp) diff --git a/others/recursive_tree_traversal.cpp b/others/recursive_tree_traversal.cpp new file mode 100644 index 000000000..ef2720101 --- /dev/null +++ b/others/recursive_tree_traversal.cpp @@ -0,0 +1,376 @@ +/** + * @file + * @brief Recursive version of Inorder, Preorder, and Postorder [Traversal of + * the Tree] (https://en.wikipedia.org/wiki/Tree_traversal) + * + * @details + * + * ### Iterative Inorder Traversal of a tree + * For traversing a (non-empty) binary tree in an inorder fashion, we must do + * these three things for every node n starting from the tree’s root: + * + * (L) Recursively traverse its left subtree. When this step is finished, + * we are back at n again. + * (N) Process n itself. + * (R) Recursively traverse its right subtree. When this step is finished, + * we are back at n again. + * + * In normal inorder traversal, we visit the left subtree before the right + * subtree. If we visit the right subtree before visiting the left subtree, it + * is referred to as reverse inorder traversal. + * + * ### Iterative Preorder Traversal of a tree + * For traversing a (non-empty) binary tree in a preorder fashion, we must do + * these three things for every node n starting from the tree’s root: + * + * (N) Process n itself. + * (L) Recursively traverse its left subtree. When this step is finished, + * we are back at n again. + * (R) Recursively traverse its right subtree. When this step is finished, + * we are back at n again. + * + * In normal preorder traversal, visit the left subtree before the right + * subtree. If we visit the right subtree before visiting the left subtree, it + * is referred to as reverse preorder traversal. + * + * ### Iterative Postorder Traversal of a tree + * For traversing a (non-empty) binary tree in a postorder fashion, we must do + * these three things for every node n starting from the tree’s root: + * + * (L) Recursively traverse its left subtree. When this step is finished, + * we are back at n again. + * (R) Recursively traverse its right subtree. When this step is finished, + * we are back at n again. + * (N) Process n itself. + * + * In normal postorder traversal, visit the left subtree before the right + * subtree. If we visit the right subtree before visiting the left subtree, it + * is referred to as reverse postorder traversal. + * + * @author [Lajat Manekar](https://github.com/Lazeeez) + * + */ + +#include /// for assert +#include /// for I/O operations +#include /// for vector + +/** + * @namespace others + * @brief Other algorithms + */ +namespace others { + +/** + * @namespace interpolation_search + * @brief Functions for the Recursive version of Inorder, Preorder, and + * Postorder [Traversal of the + * Tree](https://en.wikipedia.org/wiki/Tree_traversal) algorithm implementation + */ +namespace recursive_tree_traversals { + +/** + * @brief The structure to hold Nodes of the tree. + * @param data Value that will be stored in the node. + * @param left follow up left subtree. + * @param right follow up right subtree. + */ +struct Node { + uint64_t data = 0; ///< The value/key of the node. + struct Node *left{}; ///< struct pointer to left subtree. + struct Node *right{}; ///< struct pointer to right subtree. +}; +/** + * @brief BT used to make the entire structure of the binary tree and the + * functions associated with the binary tree + */ +class BT { + public: + std::vector + inorder_result; // vector to store the inorder traversal of the tree. + std::vector + preorder_result; // vector to store the preorder traversal of the tree. + std::vector postorder_result; // vector to store the preorder + // traversal of the tree. + + Node *createNewNode( + uint64_t); // function that will create new node for insertion. + + std::vector inorder( + Node *); // function that takes root of the tree as an argument and + // returns its inorder traversal. + std::vector preorder( + Node *); // function that takes root of the tree as an argument and + // returns its preorder traversal. + std::vector postorder( + Node *); // function that takes root of the tree as an argument and + // returns its postorder traversal. +}; + +/** + * @brief will allocate the memory for a node and, along the data and return the + * node. + * @param data value that a particular node will contain. + * @return pointer to the newly created node with assigned data. + */ +Node *BT::createNewNode(uint64_t data) { + Node *node = new Node(); + node->data = data; + node->left = node->right = nullptr; + return node; +} + +/* + * @brief inorder() function that will perform the inorder traversal + * recursively, and return the resultant vector that contain the inorder + * traversal of a tree. + * @param root head/root node of a tree + * @return result that is containing the inorder traversal of a tree + **/ +std::vector BT::inorder(Node *root) { + if (root == nullptr) { // return if the current node is empty + return {}; + } + + inorder(root->left); // Traverse the left subtree + BT::inorder_result.push_back( + root->data); // Display the data part of the root (or current node) + inorder(root->right); // Traverse the right subtree + + return inorder_result; +} + +/** + * @brief preorder function that will perform the preorder traversal + * recursively, and return the resultant vector that contain the preorder + * traversal of a tree. + * @param root head/root node of a tree + * @return result that is containing the preorder traversal of a tree + */ +std::vector BT::preorder(Node *root) { + if (root == nullptr) { // if the current node is empty + return {}; + } + + BT::preorder_result.push_back( + root->data); // Display the data part of the root (or current node) + preorder(root->left); // Traverse the left subtree + preorder(root->right); // Traverse the right subtree + + return preorder_result; +} + +/** + * @brief postorder function that will perform the postorder traversal + * recursively, and return the result vector that contain the postorder + * traversal of a tree. + * @param root head/root node of a tree + * @return result that is containing the postorder traversal of a tree + */ +std::vector BT::postorder(Node *root) { + if (root == nullptr) { // if the current node is empty + return {}; + } + + postorder(root->left); // Traverse the left subtree + postorder(root->right); // Traverse the right subtree + BT::postorder_result.push_back( + root->data); // Display the data part of the root (or current node) + + return postorder_result; +} + +} // namespace recursive_tree_traversals + +} // namespace others + +/** + * @brief 1st test-case + * @returns void + */ +void test1() { + others::recursive_tree_traversals::BT obj1; + others::recursive_tree_traversals::Node *root = obj1.createNewNode(2); + root->left = obj1.createNewNode(7); + root->right = obj1.createNewNode(5); + root->left->left = obj1.createNewNode(2); + root->left->right = obj1.createNewNode(6); + root->right->right = obj1.createNewNode(9); + root->left->right->left = obj1.createNewNode(5); + root->left->right->right = obj1.createNewNode(11); + root->right->right->left = obj1.createNewNode(4); + + std::vector actual_result_inorder{2, 7, 5, 6, 11, 2, 5, 4, 9}; + std::vector actual_result_preorder{2, 7, 2, 6, 5, 11, 5, 9, 4}; + std::vector actual_result_postorder{2, 5, 11, 6, 7, 4, 9, 5, 2}; + std::vector result_inorder; ///< result stores the inorder + ///< traversal of the binary tree + std::vector result_preorder; ///< result stores the preorder + ///< traversal of the binary tree + std::vector result_postorder; ///< result stores the postorder + ///< traversal of the binary tree + + uint64_t size = actual_result_inorder.size(); + + // Calling inorder() function by passing a root node, + // and storing the inorder traversal in result_inorder. + result_inorder = obj1.inorder(root); + std::cout << "Testcase #1: Inorder Traversal..."; + for (auto i = 0; i < size; ++i) { + assert(actual_result_inorder[i] == result_inorder[i]); + } + std::cout << "Passed!" << std::endl; + + // Calling preorder() function by passing a root node, + // and storing the preorder traversal in result_preorder. + result_preorder = obj1.preorder(root); + std::cout << "Testcase #1: Preorder Traversal..."; + for (auto i = 0; i < size; ++i) { + assert(actual_result_preorder[i] == result_preorder[i]); + } + std::cout << "Passed!" << std::endl; + + // Calling postorder() function by passing a root node, + // and storing the postorder traversal in result_postorder. + result_postorder = obj1.postorder(root); + std::cout << "Testcase #1: Postorder Traversal..."; + for (auto i = 0; i < size; ++i) { + assert(actual_result_postorder[i] == result_postorder[i]); + } + std::cout << "Passed!" << std::endl; + + std::cout << std::endl; +} + +/** + * @brief 2nd test-case + * @returns void + */ +void test2() { + others::recursive_tree_traversals::BT obj2; + others::recursive_tree_traversals::Node *root = obj2.createNewNode(1); + root->left = obj2.createNewNode(2); + root->right = obj2.createNewNode(3); + root->left->left = obj2.createNewNode(4); + root->right->left = obj2.createNewNode(5); + root->right->right = obj2.createNewNode(6); + root->right->left->left = obj2.createNewNode(7); + root->right->left->right = obj2.createNewNode(8); + + std::vector actual_result_inorder{4, 2, 1, 7, 5, 8, 3, 6}; + std::vector actual_result_preorder{1, 2, 4, 3, 5, 7, 8, 6}; + std::vector actual_result_postorder{4, 2, 7, 8, 5, 6, 3, 1}; + std::vector result_inorder; ///< result stores the inorder + ///< traversal of the binary tree + std::vector result_preorder; ///< result stores the preorder + ///< traversal of the binary tree + std::vector result_postorder; ///< result stores the postorder + ///< traversal of the binary tree + + uint64_t size = actual_result_inorder.size(); + + // Calling inorder() function by passing a root node, + // and storing the inorder traversal in result_inorder. + result_inorder = obj2.inorder(root); + std::cout << "Testcase #2: Inorder Traversal..."; + for (auto i = 0; i < size; ++i) { + assert(actual_result_inorder[i] == result_inorder[i]); + } + std::cout << "Passed!" << std::endl; + + // Calling preorder() function by passing a root node, + // and storing the preorder traversal in result_preorder. + result_preorder = obj2.preorder(root); + std::cout << "Testcase #2: Preorder Traversal..."; + for (auto i = 0; i < size; ++i) { + assert(actual_result_preorder[i] == result_preorder[i]); + } + std::cout << "Passed!" << std::endl; + + // Calling postorder() function by passing a root node, + // and storing the postorder traversal in result_postorder. + result_postorder = obj2.postorder(root); + std::cout << "Testcase #2: Postorder Traversal..."; + for (auto i = 0; i < size; ++i) { + assert(actual_result_postorder[i] == result_postorder[i]); + } + std::cout << "Passed!" << std::endl; + + std::cout << std::endl; +} + +/** + * @brief 3rd test-case + * @returns void + */ +void test3() { + others::recursive_tree_traversals::BT obj3; + others::recursive_tree_traversals::Node *root = obj3.createNewNode(1); + root->left = obj3.createNewNode(2); + root->right = obj3.createNewNode(3); + root->left->left = obj3.createNewNode(4); + root->left->right = obj3.createNewNode(5); + + std::vector actual_result_inorder{4, 2, 5, 1, 3}; + std::vector actual_result_preorder{1, 2, 4, 5, 3}; + std::vector actual_result_postorder{4, 5, 2, 3, 1}; + std::vector result_inorder; ///< result stores the inorder + ///< traversal of the binary tree + std::vector result_preorder; ///< result stores the preorder + ///< traversal of the binary tree + std::vector result_postorder; ///< result stores the postorder + ///< traversal of the binary tree + + uint64_t size = actual_result_inorder.size(); + + // Calling inorder() function by passing a root node, + // and storing the inorder traversal in result_inorder. + + result_inorder = obj3.inorder(root); + std::cout << "Testcase #3: Inorder Traversal..."; + for (auto i = 0; i < size; ++i) { + assert(actual_result_inorder[i] == result_inorder[i]); + } + std::cout << "Passed!" << std::endl; + + // Calling preorder() function by passing a root node, + // and storing the preorder traversal in result_preorder. + result_preorder = obj3.preorder(root); + std::cout << "Testcase #3: Preorder Traversal..."; + for (auto i = 0; i < size; ++i) { + assert(actual_result_preorder[i] == result_preorder[i]); + } + std::cout << "Passed!" << std::endl; + + // Calling postorder() function by passing a root node, + // and storing the postorder traversal in result_postorder. + result_postorder = obj3.postorder(root); + std::cout << "Testcase #3: Postorder Traversal..."; + for (auto i = 0; i < size; ++i) { + assert(actual_result_postorder[i] == result_postorder[i]); + } + std::cout << "Passed!" << std::endl; + + std::cout << std::endl; +} + +/** + * @brief Self-test implementations + * @returns void + */ +static void tests() { + std::cout << "1st test-case" << std::endl; + test1(); // run 1st test-case + std::cout << "2nd test-case" << std::endl; + test2(); // run 2nd test-case + std::cout << "3rd test-case" << std::endl; + test3(); // run 3rd test-case +} +/** + * @brief Main function + * @returns 0 on exit + */ +int main() { + tests(); // run self-test implementations + return 0; +}