From 47c84137eec683790faa494ac0068d7c9f88f8ff Mon Sep 17 00:00:00 2001 From: Motasim <44056349+motasimmakki@users.noreply.github.com> Date: Tue, 6 Jul 2021 06:02:41 +0530 Subject: [PATCH] feat: Added implementation of iterative version of tree traversals. (#1506) * feat: Added iterative version of tree traversals. Here is the implementation of the iterative version of the Preorder, Postorder, and the Inorder traversal of given tree. . Time Complexity: O(n), where 'n' is the total number of nodes in a tree. * updating DIRECTORY.md * fixed: function descriptions, namespace declaration, and included separate libraries. * fixed: added range bases for loops. * style: proper indentation Co-authored-by: David Leal * style: proper indentation Co-authored-by: David Leal * style: proper indentation Co-authored-by: David Leal * fix: C style NULL to nullptr Co-authored-by: David Leal * docs: spell correction Co-authored-by: David Leal * style: formatted comments. * fixes: static_cast, if and for statement braces * style: modified pointer declaration. * fixes: removed use of typedef, renamed BT to Node * Fix `clang-tidy` warnings * fix: Try to fix `clang-tidy` warnings this time * docs: Proper function description Co-authored-by: Mann Patel <46739555+manncodes@users.noreply.github.com> * fix: Class based approach * docs: Proper formatted comment Co-authored-by: David Leal * docs: Proper indentation Co-authored-by: David Leal * fix: Initialized data variable Co-authored-by: David Leal * docs: Proper formatted comment Co-authored-by: David Leal * docs: Proper indentation Co-authored-by: David Leal * docs: Proper formatted comment Co-authored-by: David Leal * docs: Proper function description Co-authored-by: David Leal * docs: Removed unnecessary comment Co-authored-by: David Leal * docs: Proper formatted comment Co-authored-by: David Leal * docs: Proper function description * docs: Proper variables description Co-authored-by: Mann Patel <46739555+manncodes@users.noreply.github.com> * docs: Included variables description Co-authored-by: Mann Patel <46739555+manncodes@users.noreply.github.com> * docs: Included variables description Co-authored-by: Mann Patel <46739555+manncodes@users.noreply.github.com> * docs: Proper variables description Co-authored-by: Mann Patel <46739555+manncodes@users.noreply.github.com> * fixes: Self-test implementation and namespace * docs: Documentation improvements * docs: Proper formatted description Co-authored-by: David Leal * docs: Proper formatted description Co-authored-by: David Leal * docs: Proper formatted description Co-authored-by: David Leal * docs: Proper formatted description Co-authored-by: David Leal * docs: Proper indentation Co-authored-by: David Leal * docs: Proper formatted description Co-authored-by: David Leal * docs: Improved function description * docs: Proper formatted description Co-authored-by: David Leal * test: Added test cases for negative values * docs: Proper description Co-authored-by: David Leal * docs: Proper formatted comment Co-authored-by: David Leal * docs: Proper formatted comment Co-authored-by: David Leal * docs: Proper function description Co-authored-by: David Leal * docs: Proper formatted description Co-authored-by: David Leal * docs: Proper description Co-authored-by: David Leal * docs: Proper description Co-authored-by: David Leal Co-authored-by: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Co-authored-by: David Leal Co-authored-by: Mann Patel <46739555+manncodes@users.noreply.github.com> --- DIRECTORY.md | 1 + others/iterative_tree_traversals.cpp | 362 +++++++++++++++++++++++++++ 2 files changed, 363 insertions(+) create mode 100644 others/iterative_tree_traversals.cpp diff --git a/DIRECTORY.md b/DIRECTORY.md index ccbc5c68f..f735080e1 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -229,6 +229,7 @@ * [Decimal To Roman Numeral](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/others/decimal_to_roman_numeral.cpp) * [Fast Integer Input](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/others/fast_integer_input.cpp) * [Happy Number](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/others/happy_number.cpp) + * [Iterative Tree Traversals](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/others/iterative_tree_traversals.cpp) * [Matrix Exponentiation](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/others/matrix_exponentiation.cpp) * [Palindrome Of Number](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/others/palindrome_of_number.cpp) * [Paranthesis Matching](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/others/paranthesis_matching.cpp) diff --git a/others/iterative_tree_traversals.cpp b/others/iterative_tree_traversals.cpp new file mode 100644 index 000000000..6d0e7dc2e --- /dev/null +++ b/others/iterative_tree_traversals.cpp @@ -0,0 +1,362 @@ +/** + * @file + * @brief Iterative version of Preorder, Postorder, and preorder [Traversal of the Tree] + * (https://en.wikipedia.org/wiki/Tree_traversal) + * @author [Motasim](https://github.com/motasimmakki) + * @details + * + * ### Iterative Preorder Traversal of a tree + * Create a Stack that will store the Node of Tree. + * Push the root node into the stack. + * Save the root into the variabe named as current, and pop and elemnt from the stack. + * Store the data of current into the result array, and start traversing from it. + * Push both the child node of the current node into the stack, first right child then left child. + * Repeat the same set of steps untill the Stack becomes empty. + * And return the result array as the preorder traversal of a tree. + * + * ### Iterative Postorder Traversal of a tree + * Create a Stack that will store the Node of Tree. + * Push the root node into the stack. + * Save the root into the variabe named as current, and pop and elemnt from the stack. + * Store the data of current into the result array, and start traversing from it. + * Push both the child node of the current node into the stack, first left child then right child. + * Repeat the same set of steps untill the Stack becomes empty. + * Now reverse the result array and then return it to the calling function as a postorder traversal of a tree. + * + * ### Iterative Inorder Traversal of a tree + * Create a Stack that will store the Node of Tree. + * Push the root node into the stack. + * Save the root into the variabe named as current. + * Now iterate and take the current to the extreme left of the tree by traversing only to its left. + * Pop the elemnt from the stack and assign it to the current. + * Store the data of current into the result array. + * Repeat the same set of steps until the Stack becomes empty or the current becomes NULL. + * And return the result array as the inorder traversal of a tree. + */ +#include /// for I/O operations +#include /// for `stack` +#include /// for `vector` +#include /// for `reverse` +#include /// for `assert` + +/** + * @namespace others + * @brief Other algorithms + */ +namespace others { +/** + * @namespace iterative_tree_traversals + * @brief Functions for the [Traversal of the Tree](https://en.wikipedia.org/wiki/Tree_traversal) algorithm + */ +namespace iterative_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 preOrderIterative(Node *); ///< function that takes root of the tree as an argument, and returns its preorder traversal. + std::vector postOrderIterative(Node *); ///< function that takes root of the tree as an argument, and returns its postorder traversal. + std::vector inOrderIterative(Node *); ///< function that takes root of the tree as an argument, and returns its inorder 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) { + Node *node = new Node(); + node->data = data; + node->left = node->right = nullptr; + return node; +} + +/** + * @brief preOrderIterative() function that will perform the preorder traversal iteratively, + * 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::preOrderIterative(Node *root) { + std::stack stack; ///< is used to find and traverse the child nodes. + std::vector result; ///< list of values, sorted in pre-order. + + stack.push(root); + + while(!stack.empty()) { + result.push_back(stack.top()->data); + Node *current = stack.top(); + stack.pop(); + + if(current->right) { + stack.push(current->right); + } + if(current->left) { + stack.push(current->left); + } + } + + return result; +} + +/** + * @brief postOrderIterative() function that will perform the postorder traversal iteratively, + * 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::postOrderIterative(Node *root) { + std::stack stack; ///< is used to find and traverse the child nodes. + std::vector result; ///< List of values, sorted in post-order. + + stack.push(root); + + while(!stack.empty()) { + result.push_back(stack.top()->data); + Node *current = stack.top(); + stack.pop(); + + if(current->left) { + stack.push(current->left); + } + if(current->right) { + stack.push(current->right); + } + } + + reverse(result.begin(), result.end()); + + return result; +} + +/** + * @brief inOrderIterative() function that will perform the inorder traversal iteratively, + * 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::inOrderIterative(Node *root) { + std::stack stack; ///< is used to find and traverse the child nodes. + std::vector result; ///< List of values, sorted in in-order. + + Node *current = root; + + while(!stack.empty() || current) { + while(current) { + stack.push(current); + current = current->left; + } + current = stack.top(); + stack.pop(); + result.push_back(current->data); + current = current->right; + } + return result; +} +} // namespace iterative_tree_traversals +} // namespace others + +/** + * @brief Test the computed preorder with the actual preorder. + * @param binaryTree instance of the BinaryTree class + * @param root head/root node of a tree + */ +static void test1(others::iterative_tree_traversals::BinaryTree binaryTree, others::iterative_tree_traversals::Node *root){ + std::vector actual_result{1, 2, 4, 5, 3}; + std::vector result; ///< result stores the preorder traversal of the binary tree + + // Calling preOrderIterative() function by passing a root node, + // and storing the preorder traversal in result. + result = binaryTree.preOrderIterative(root); + + // Self-testing the result using `assert` + for(int i = 0; i < result.size(); i++) + assert(actual_result[i] == result[i]); + + // Printing the result storing preorder. + std::cout<< "\nPreOrder Traversal Is : "<< std::endl; + for(auto i: result) { + std::cout<< i<< " "; + } +} + +/** + * @brief Test the computed postorder with the actual postorder. + * @param binaryTree instance of BinaryTree class + * @param root head/root node of a tree + */ +static void test2(others::iterative_tree_traversals::BinaryTree binaryTree, others::iterative_tree_traversals::Node *root){ + std::vector actual_result{4, 5, 2, 3, 1}; + std::vector result; ///< result stores the postorder traversal of the binary tree. + + // Calling postOrderIterative() function by passing a root node, + // and storing the postorder traversal in result. + result = binaryTree.postOrderIterative(root); + + // Self-testing the result using `assert` + for(int i = 0; i < result.size(); i++) + assert(actual_result[i] == result[i]); + + // Printing the result storing postorder. + std::cout<< "\nPostOrder Traversal Is : "<< std::endl; + for(auto i: result) { + std::cout<< i<< " "; + } +} + +/** + * @brief Test the computed inorder with the actual inorder. + * @param binaryTree instance of BinaryTree class + * @param root head/root node of a tree + */ +static void test3(others::iterative_tree_traversals::BinaryTree binaryTree, others::iterative_tree_traversals::Node *root){ + std::vector actual_result{4, 2, 5, 1, 3}; + std::vector result; ///< result stores the inorder traversal of the binary tree. + + // Calling inOrderIterative() function by passing a root node, + // and storing the inorder traversal in result. + result = binaryTree.inOrderIterative(root); + + // Self-testing the result using `assert` + for(int i = 0; i < result.size(); i++) + assert(actual_result[i] == result[i]); + + // Printing the result storing inorder. + std::cout<< "\nInOrder Traversal Is : "<< std::endl; + for(auto i: result) { + std::cout<< i<< " "; + } +} + +/** + * @brief Test the computed preorder with the actual preorder on negative value. + * @param binaryTree instance of BinaryTree class + * @param root head/root node of a tree + */ +static void test4(others::iterative_tree_traversals::BinaryTree binaryTree, others::iterative_tree_traversals::Node *root){ + std::vector actual_result{-1, -2, -4, -5, -3}; + std::vector result; ///< result stores the preorder traversal of the binary tree + + // Calling preOrderIterative() function by passing a root node, + // and storing the preorder traversal in result. + result = binaryTree.preOrderIterative(root); + + // Self-testing the result using `assert` + for(int i = 0; i < result.size(); i++) + assert(actual_result[i] == result[i]); + + // Printing the result storing preorder. + std::cout<< "\nPreOrder Traversal Is : "<< std::endl; + for(auto i: result) { + std::cout<< i<< " "; + } +} + +/** + * @brief Test the computed postorder with the actual postorder on negative value. + * @param binaryTree instance of BinaryTree class + * @param root head/root node of a tree + */ +static void test5(others::iterative_tree_traversals::BinaryTree binaryTree, others::iterative_tree_traversals::Node *root){ + std::vector actual_result{-4, -5, -2, -3, -1}; + std::vector result; ///< result stores the postorder traversal of the binary tree. + + // Calling postOrderIterative() function by passing a root node, + // and storing the postorder traversal in result. + result = binaryTree.postOrderIterative(root); + + // Self-testing the result using `assert` + for(int i = 0; i < result.size(); i++) + assert(actual_result[i] == result[i]); + + // Printing the result storing postorder. + std::cout<< "\nPostOrder Traversal Is : "<< std::endl; + for(auto i: result) { + std::cout<< i<< " "; + } +} + +/** + * @brief Test the computed inorder with the actual inorder on negative value. + * @param binaryTree instance of BinaryTree class + * @param root head/root node of a tree + */ +static void test6(others::iterative_tree_traversals::BinaryTree binaryTree, others::iterative_tree_traversals::Node *root){ + std::vector actual_result{-4, -2, -5, -1, -3}; + std::vector result; ///< result stores the inorder traversal of the binary tree. + + // Calling inOrderIterative() function by passing a root node, + // and storing the inorder traversal in result. + result = binaryTree.inOrderIterative(root); + + // Self-testing the result using `assert` + for(int i = 0; i < result.size(); i++) + assert(actual_result[i] == result[i]); + + // Printing the result storing inorder. + std::cout<< "\nInOrder Traversal Is : "<< std::endl; + for(auto i: result) { + std::cout<< i<< " "; + } +} + +/** + * @brief Main function + * @returns 0 on exit + */ +int main() { + // Creating a tree with the following structure, + /* + 1 + / \ + 2 3 + / \ + 4 5 + */ + + others::iterative_tree_traversals::BinaryTree binaryTree; ///< instace of BinaryTree, used to access its members functions. + others::iterative_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::cout<< "\n| Tests for positive data value |"<< std::endl; + test1(binaryTree, root); // run preorder-iterative test + std::cout<< "\nPre-order test Passed!"<< std::endl; + + test2(binaryTree, root); // run postorder-iterative test + std::cout<< "\nPost-order test Passed!"<< std::endl; + + test3(binaryTree, root); // run inorder-iterative test + std::cout<< "\nIn-order test Passed!"<< std::endl; + + // Modifying tree for negative values. + root->data = -1; + root->left->data = -2; + root->right->data = -3; + root->left->left->data = -4; + root->left->right->data = -5; + + std::cout<< "\n| Tests for negative data values |"<< std::endl; + test4(binaryTree, root); // run preorder-iterative test on negative values + std::cout<< "\nPre-order test on-negative value Passed!"<< std::endl; + + test5(binaryTree, root); // run postorder-iterative test on negative values + std::cout<< "\nPost-order test on-negative value Passed!"<< std::endl; + + test6(binaryTree, root); // run inorder-iterative test on negative values + std::cout<< "\nIn-order test on-negative value Passed!"<< std::endl; + + return 0; +}