Write a recursive algorithm for pre-order traversal in a binary tree.
Preorder Tree Traversal – Iterative and Recursive
Given a binary tree, write an iterative and recursive solution to traverse the tree using preorder traversal in C++, Java, and Python.
Unlike linked lists, one-dimensional arrays, and other linear data structures, which are traversed in linear order, trees can be traversed in multiple ways in depth–first order (preorder, inorder, and postorder) or breadth–first order (level order traversal). Beyond these basic traversals, various more complex or hybrid schemes are possible, such as depth-limited searches like iterative deepening depth–first search. In this post, preorder tree traversal is discussed in detail.
Traversing a tree involves iterating over all nodes in some manner. As the tree is not a linear data structure, there can be more than one possible next node from a given node, so some nodes must be deferred, i.e., stored in some way for later visiting. The traversal can be done iteratively where the deferred nodes are stored in the stack, or it can be done by recursion, where the deferred nodes are stored implicitly in the call stack.
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.
Recursive Implementation
As we can see, only after processing any node, the left subtree is processed, followed by the right subtree. 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.
Following is the C++, Java, and Python program that demonstrates it:
- C++
- Java
- Python
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 | #include <iostream> using namespace std; // Data structure to store a binary tree node struct Node { int data; Node *left, *right; Node(int data) { this->data = data; this->left = this->right = nullptr; } }; // Recursive function to perform preorder traversal on the tree void preorder(Node* root) { // if the current node is empty if (root == nullptr) { return; } // Display the data part of the root (or current node) cout << root->data << " "; // Traverse the left subtree preorder(root->left); // Traverse the right subtree preorder(root->right); } int main() { /* Construct the following tree 1 / \ / \ 2 3 / / \ / / \ 4 5 6 / \ / \ 7 8 */ Node* root = new Node(1); root->left = new Node(2); root->right = new Node(3); root->left->left = new Node(4); root->right->left = new Node(5); root->right->right = new Node(6); root->right->left->left = new Node(7); root->right->left->right = new Node(8); preorder(root); return 0; } |
Iterative Implementation
To convert the above recursive procedure into an iterative one, we need an explicit stack. Following is a simple stack-based iterative algorithm to perform preorder traversal:
if (node = null)
return
s —> empty stack
s.push(node)
while (not s.isEmpty())
node —> s.pop()
visit(node)
if (node.right != null)
s.push(node.right)
if (node.left != null)
s.push(node.left)
The algorithm can be implemented as follows in C++, Java, and Python:
- C++
- Java
- Python
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 | #include <iostream> #include <stack> using namespace std; // Data structure to store a binary tree node struct Node { int data; Node *left, *right; Node(int data) { this->data = data; this->left = this->right = nullptr; } }; // Iterative function to perform preorder traversal on the tree void preorderIterative(Node* root) { // return if the tree is empty if (root == nullptr) return; // create an empty stack and push the root node stack<Node*> stack; stack.push(root); // loop till stack is empty while (!stack.empty()) { // pop a node from the stack and print it Node* curr = stack.top(); stack.pop(); cout << curr->data << " "; // push the right child of the popped node into the stack if (curr->right) { stack.push(curr->right); } // push the left child of the popped node into the stack if (curr->left) { stack.push(curr->left); } // the right child must be pushed first so that the left child // is processed first (LIFO order) } } int main() { /* Construct the following tree 1 / \ / \ 2 3 / / \ / / \ 4 5 6 / \ / \ 7 8 */ Node* root = new Node(1); root->left = new Node(2); root->right = new Node(3); root->left->left = new Node(4); root->right->left = new Node(5); root->right->right = new Node(6); root->right->left->left = new Node(7); root->right->left->right = new Node(8); preorderIterative(root); return 0; } |
The above solution can be further optimized by pushing only the right children to the stack.
- C++
- Java
- Python
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 | #include <iostream> #include <stack> using namespace std; // Data structure to store a binary tree node struct Node { int data; Node *left, *right; Node(int data) { this->data = data; this->left = this->right = nullptr; } }; // Iterative function to perform preorder traversal on the tree void preorderIterative(Node* root) { // return if the tree is empty if (root == nullptr) { return; } // create an empty stack and push the root node stack<Node*> stack; stack.push(root); // start from the root node (set current node to the root node) Node* curr = root; // loop till stack is empty while (!stack.empty()) { // if the current node exists, print it and push its right child // to the stack before moving to its left child if (curr != nullptr) { cout << curr->data << " "; if (curr->right) { stack.push(curr->right); } curr = curr->left; } // if the current node is null, pop a node from the stack // set the current node to the popped node else { curr = stack.top(); stack.pop(); } } } int main() { /* Construct the following tree 1 / \ / \ 2 3 / / \ / / \ 4 5 6 / \ / \ 7 8 */ Node* root = new Node(1); root->left = new Node(2); root->right = new Node(3); root->left->left = new Node(4); root->right->left = new Node(5); root->right->right = new Node(6); root->right->left->left = new Node(7); root->right->left->right = new Node(8); preorderIterative(root); return 0; } |
The time complexity of the above solutions is O(n), where n
is the total number of nodes in the binary tree. The space complexity of the program is O(n) as the space required is proportional to the tree’s height, which can be equal to the total number of nodes in the tree in the worst case for skewed trees.
Tirthankar Pal
MBA from IIT Kharagpur with GATE, GMAT, IIT Kharagpur Written Test, and Interview
2 year PGDM (E-Business) from Welingkar, Mumbai
4 years of Bachelor of Science (Hons) in Computer Science from the National Institute of Electronics and Information Technology
Google and Hubspot Certification
Brain Bench Certification in C++, VC++, Data Structure and Project Management
10 years of Experience in Software Development out of that 6 years 8 months in Wipro
Selected in Six World Class UK Universities:-
King's College London, Durham University, University of Exeter, University of Sheffield, University of Newcastle, University of Leeds
No comments:
Post a Comment