diff --git a/others/recursive_tree_traversals.cpp b/others/recursive_tree_traversals.cpp new file mode 100644 index 000000000..1a1e49ec1 --- /dev/null +++ b/others/recursive_tree_traversals.cpp @@ -0,0 +1,493 @@ +/******************************************************************************** + * @file + * @brief Recursive version of Inorder, Preorder, and Postorder [Traversal of + *the Tree] (https://en.wikipedia.org/wiki/Tree_traversal) + * @author [Lajat Manekar](https://github.com/Lazeeez) + * @details + * + * ### Recursive Inorder Traversal of a tree + * Before processing any node, the left subtree is processed first, followed by + * the node, and the right subtree is processed at last. These operations can + * be defined recursively for each node. The recursive implementation is + *referred to as a Depth-First Search (DFS), as the search tree is deepened as + *much as possible on each child before going to the next sibling. + * + * ### Recursive Preorder Traversal of a tree + * Only after processing any node, the left subtree is processed, followed by + * the right subtree is processed. These operations can be defined recursively + * for each node. The recursive implementation is referred to as a Depth-First + *Search (DFS), as the search tree is deepened as much as possible on each child + *before going to the next sibling. + * + * ### Recursive Postorder Traversal of a tree + * Before processing any node, the left subtree is processed first, followed by + * the right subtree, and the node is processed at last. These operations can + * be defined recursively for each node. The recursive implementation is + *referred to as a Depth-First Search (DFS), as the search tree is deepened as + *much as possible on each child before going to the next sibling. + *******************************************************************************/ +#include /// for `assert` +#include /// for I/O operations +#include /// for `vector` + +/******************************************************************************** + *@namespace Results + *@brief To be used to store the results + *******************************************************************************/ +namespace results { + +std::vector inorder_result; ///< list of values, sorted in in-order. +std::vector preorder_result; ///< list of values, sorted in pre-order. +std::vector + postorder_result; ///< list of values, sorted in post-order. +} // namespace results + +/******************************************************************************** + * @namespace others + * @brief Other algorithms + *******************************************************************************/ +namespace others { + +/******************************************************************************* + * @namespace recursive_tree_traversals + * @brief Functions for the [Traversal of the + *Tree](https://en.wikipedia.org/wiki/Tree_traversal) algorithm + *******************************************************************************/ +namespace recursive_tree_traversals { + +/******************************************************************************* + * @brief Defines the structure of a node of the tree + *******************************************************************************/ +struct Node { + int64_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 Defines the functions associated with the binary tree + *******************************************************************************/ +class BinaryTree { + public: + Node *createNewNode( + int64_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 postorder 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 *BinaryTree::createNewNode(int64_t data) { + auto *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 result array 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 BinaryTree::inorder(Node *root) { + if (root == nullptr) { ///< return if the current node is empty + return {}; + } + + BinaryTree::inorder(root->left); ///< Traverse the left subtree + results::inorder_result.push_back( + root->data); ///< Display the data part of the root (or current node) + BinaryTree::inorder(root->right); ///< Traverse the right subtree + return results::inorder_result; +} + +/******************************************************************************* + * @brief preorder() function that will perform the preorder traversal + *recursively, and return the result array 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 BinaryTree::preorder(Node *root) { + if (root == nullptr) { ///< if the current node is empty + return {}; + } + + results::preorder_result.push_back( + root->data); ///< Display the data part of the root (or current node) + BinaryTree::preorder(root->left); ///< Traverse the left subtree + BinaryTree::preorder(root->right); ///< Traverse the right subtree + return results::preorder_result; +} + +/******************************************************************************* + * @brief postorder() function that will perform the postorder traversal + *recursively, and return the result array 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 BinaryTree::postorder(Node *root) { + if (root == nullptr) { ///< if the current node is empty + return {}; + } + + BinaryTree::postorder(root->left); ///< Traverse the left subtree + BinaryTree::postorder(root->right); ///< Traverse the right subtree + results::postorder_result.push_back( + root->data); ///< Display the data part of the root (or current node) + return results::postorder_result; +} +} // namespace recursive_tree_traversals +} // namespace others + +/******************************************************************************* + * @brief Self-test implementations #1 + * @returns void + *******************************************************************************/ + +static void test1() { + /******************************************************************************* + * Creating a tree with the following structure. + * 2 + * / \ + * / \ + * 7 5 + * / \ \ + * 2 6 9 + * / \ / + * 5 11 4 + * + *******************************************************************************/ + + others::recursive_tree_traversals::BinaryTree + binaryTree; ///< instace of BinaryTree, used to access its members + ///< functions. + others::recursive_tree_traversals::Node *root = binaryTree.createNewNode(2); + + root->left = binaryTree.createNewNode(7); + root->right = binaryTree.createNewNode(5); + root->left->left = binaryTree.createNewNode(2); + root->left->right = binaryTree.createNewNode(6); + root->right->right = binaryTree.createNewNode(9); + root->left->right->left = binaryTree.createNewNode(5); + root->left->right->right = binaryTree.createNewNode(11); + root->right->right->left = binaryTree.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; + std::vector result_preorder; + std::vector result_postorder; + + uint64_t size = actual_result_inorder.size(); + + // inorder traversal + result_inorder = binaryTree.inorder( + root); ///< Calling inorder() function by passing a root node and + ///< storing the inorder traversal in result_inorder. + std::cout << "Test1 Inorder Traversal..."; + for (int i = 0; i < size; ++i) { + assert(actual_result_inorder[i] == + result_inorder[i]); ///< Self-testing the result using `assert` + } + std::cout << "Passed" << std::endl; + + // preorder traversal + result_preorder = binaryTree.preorder( + root); ///< Calling preorder() function by passing a root node and + ///< storing the preorder traversal in result_preorder. + std::cout << "Test1 Preorder Traversal..."; + for (int i = 0; i < size; ++i) { + assert(actual_result_preorder[i] == + result_preorder[i]); ///< Self-testing the result using `assert` + } + std::cout << "Passed" << std::endl; + + // postorder traversal + result_postorder = binaryTree.postorder( + root); ///< Calling postorder() function by passing a root node and + ///< storing the postorder traversal in result_postorder. + std::cout << "Test1 Postorder Traversal..."; + for (int i = 0; i < size; ++i) { + assert( + actual_result_postorder[i] == + result_postorder[i]); ///< Self-testing the result using `assert` + } + std::cout << "Passed" << std::endl; + + std::cout << std::endl; +} + +/******************************************************************************* + * @brief Self-test implementations #2 + * @returns void + *******************************************************************************/ + +static void test2() { + /******************************************************************************* + * Creating a tree with the following structure. + * 1 + * / \ + * / \ + * 2 3 + * / / \ + * 4 5 6 + * / \ + * 7 8 + * + * + *******************************************************************************/ + + others::recursive_tree_traversals::BinaryTree + binaryTree; ///< instace of BinaryTree, used to access its members + ///< functions. + others::recursive_tree_traversals::Node *root = binaryTree.createNewNode(1); + + root->left = binaryTree.createNewNode(2); + root->right = binaryTree.createNewNode(3); + root->left->left = binaryTree.createNewNode(4); + root->right->left = binaryTree.createNewNode(5); + root->right->right = binaryTree.createNewNode(6); + root->right->left->left = binaryTree.createNewNode(7); + root->right->left->right = binaryTree.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; + std::vector result_preorder; + std::vector result_postorder; + + uint64_t size = actual_result_inorder.size(); + + // inorder traversal + result_inorder = binaryTree.inorder( + root); ///< Calling inorder() function by passing a root node and + ///< storing the inorder traversal in result_inorder. + std::cout << "Test2 Inorder Traversal..."; + for (int i = 0; i < size; ++i) { + assert(actual_result_inorder[i] == + result_inorder[i]); ///< Self-testing the result using `assert` + } + std::cout << "Passed" << std::endl; + + // preorder traversal + result_preorder = binaryTree.preorder( + root); ///< Calling preorder() function by passing a root node and + ///< storing the preorder traversal in result_preorder. + std::cout << "Test2 Preorder Traversal..."; + for (int i = 0; i < size; ++i) { + assert(actual_result_preorder[i] == + result_preorder[i]); ///< Self-testing the result using `assert` + } + std::cout << "Passed" << std::endl; + + // postorder traversal + result_postorder = binaryTree.postorder( + root); ///< Calling postorder() function by passing a root node and + ///< storing the postorder traversal in result_postorder. + std::cout << "Test2 Postorder Traversal..."; + for (int i = 0; i < size; ++i) { + assert( + actual_result_postorder[i] == + result_postorder[i]); ///< Self-testing the result using `assert` + } + std::cout << "Passed" << std::endl; + + std::cout << std::endl; +} + +/******************************************************************************* + * @brief Self-test implementations #3 + * @returns void + *******************************************************************************/ + +static void test3() { + /******************************************************************************* + * Creating a tree with the following structure. + * 1 + * / \ + * 2 3 + * / \ + * 4 5 + * + *******************************************************************************/ + + others::recursive_tree_traversals::BinaryTree + binaryTree; ///< instace of BinaryTree, used to access its members + ///< functions. + others::recursive_tree_traversals::Node *root = binaryTree.createNewNode(1); + + root->left = binaryTree.createNewNode(2); + root->right = binaryTree.createNewNode(3); + root->left->left = binaryTree.createNewNode(4); + root->left->right = binaryTree.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; + std::vector result_preorder; + std::vector result_postorder; + + uint64_t size = actual_result_inorder.size(); + + // inorder traversal + result_inorder = binaryTree.inorder( + root); ///< Calling inorder() function by passing a root node and + ///< storing the inorder traversal in result_inorder. + std::cout << "Test3 Inorder Traversal..."; + for (int i = 0; i < size; ++i) { + assert(actual_result_inorder[i] == + result_inorder[i]); ///< Self-testing the result using `assert` + } + std::cout << "Passed" << std::endl; + + // preorder traversal + result_preorder = binaryTree.preorder( + root); ///< Calling preorder() function by passing a root node and + ///< storing the preorder traversal in result_preorder. + std::cout << "Test3 Preorder Traversal..."; + for (int i = 0; i < size; ++i) { + assert(actual_result_preorder[i] == + result_preorder[i]); ///< Self-testing the result using `assert` + } + std::cout << "Passed" << std::endl; + + // postorder traversal + result_postorder = binaryTree.postorder( + root); ///< Calling postorder() function by passing a root node and + ///< storing the postorder traversal in result_postorder. + std::cout << "Test3 Postorder Traversal..."; + for (int i = 0; i < size; ++i) { + assert( + actual_result_postorder[i] == + result_postorder[i]); ///< Self-testing the result using `assert` + } + std::cout << "Passed" << std::endl; + + std::cout << std::endl; +} + +/******************************************************************************* + * @brief Self-test implementations #4 + * @returns void + *******************************************************************************/ + +static void test4() { ///< Testcase with negative numbers + /******************************************************************************* + * Creating a tree with the following structure. + * -1 + * / \ + * -2 -3 + * / \ + * -4 -5 + * + *******************************************************************************/ + + others::recursive_tree_traversals::BinaryTree + binaryTree; ///< instace of BinaryTree, used to access its members + ///< functions. + others::recursive_tree_traversals::Node *root = binaryTree.createNewNode(1); + + root->left = binaryTree.createNewNode(2); + root->right = binaryTree.createNewNode(3); + root->left->left = binaryTree.createNewNode(4); + root->left->right = binaryTree.createNewNode(5); + + root->data = -1; + root->left->data = -2; + root->right->data = -3; + root->left->left->data = -4; + root->left->right->data = -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; + std::vector result_preorder; + std::vector result_postorder; + + uint64_t size = actual_result_inorder.size(); + + // inorder traversal + result_inorder = binaryTree.inorder( + root); ///< run inorder-recursive test on negative values + std::cout << "Test4 Inorder Traversal..."; + for (int i = 0; i < size; ++i) { + assert(actual_result_inorder[i] == + result_inorder[i]); ///< Self-testing the result using `assert` + } + std::cout << "Passed" << std::endl; + + // preorder traversal + result_preorder = binaryTree.preorder( + root); ///< run preorder-recursive test on negative values + std::cout << "Test4 Preorder Traversal..."; + for (int i = 0; i < size; ++i) { + assert(actual_result_preorder[i] == + result_preorder[i]); ///< Self-testing the result using `assert` + } + std::cout << "Passed" << std::endl; + + // postorder traversal + result_postorder = binaryTree.postorder( + root); ///< run postorder-recursive test on negative values + std::cout << "Test4 Postorder Traversal..."; + for (int i = 0; i < size; ++i) { + assert( + actual_result_postorder[i] == + result_postorder[i]); ///< Self-testing the result using `assert` + } + std::cout << "Passed" << std::endl; + + std::cout << std::endl; +} + +/******************************************************************************** + * @brief Main function + * @returns 0 on exit + *******************************************************************************/ + +int main() { + std::cout << "TestCase #1" << std::endl; ///< Testcase #1 + test1(); + results::inorder_result.clear(); + results::preorder_result.clear(); + results::postorder_result.clear(); + + std::cout << "TestCase #2" << std::endl; ///< Testcase #2 + test2(); + results::inorder_result.clear(); + results::preorder_result.clear(); + results::postorder_result.clear(); + + std::cout << "TestCase #3" << std::endl; ///< Testcase #3 + test3(); + results::inorder_result.clear(); + results::preorder_result.clear(); + results::postorder_result.clear(); + + std::cout << "TestCase #4" << std::endl; ///< Testcase #4 + test4(); + results::inorder_result.clear(); + results::preorder_result.clear(); + results::postorder_result.clear(); + + return 0; +} \ No newline at end of file