Tree Traversal: Inorder, Preorder, Postorder, and Level-order
Data structures and algorithms form a big portion of the topics you need to cover when it comes to tech interview preparation. Software engineers or developers need to be masters of the basics to be able to solve the tough problems presented at FAANG and tier-1 tech company interviews. In this article, we will cover a few important topics that will help you in your prep — inorder tree traversal, preorder tree traversal, postorder tree traversal, and level-order traversal.
Specifically, we’ll cover:
- What Is Tree Traversal?
- Inorder Tree Traversal
- Preorder Tree Traversal
- Postorder Tree Traversal
- Level-order Tree Traversal
- Implementation of Tree Traversal
- Time and Space Complexity of Tree Traversal Algorithms
- Examples of Tech Interview Questions on Tree Traversals
- FAQs on Tree Traversals
Introduction
A tree is a hierarchical data structure, its property to store the information in a hierarchy makes it different from linear data structures like linked lists, stacks, and others. The tree contains nodes(data) and edges (which connect two nodes) that do not form cycles.
Traversing the tree means visiting all the nodes in the tree. For example, you can find the sum of all of the values stored in the tree nodes or find the largest one. For all of these operations, we need to visit every node in the tree.
For linear data structures, such as arrays, stacks, queues, and linked lists, there is only one way to store the data. However, in a hierarchical data structure, such as a tree, we can store the data in many ways.
What Is Tree Traversal?
Tree traversals are the algorithms used to traverse the tree in different orders. Each of these algorithms can be defined recursively. In tree traversals, we visit each node in a tree and perform some operations on it, like printing the nodes, etc.
Tree traversal algorithms are classified into two:
We can picture a tree as a recursive structure; DFS traversals can be implemented recursively. When we’re at a node, three actions can occur: perform some operation on the current node (like print the value stored in it), traverse the left subtree, and traverse the right subtree. Based on this nature, we have the following types of DFS traversal of a tree:
- Tree Traversal Inorder: In inorder tree traversal, we traverse left, perform some operation on the current node (in this article, we are printing the value stored in it), then traverse right.
- Tree Traversal Preorder: In preorder tree traversal, we perform some operation on the current node, traverse left, traverse right
- Tree Traversal Postorder: In postorder tree traversal, we traverse left, traverse right, Perform some operation on the current node
Inorder Tree Traversal
Inorder tree traversal is one of the most widely used variants of DFS tree traversal.
In inorder tree traversal, we first process the left subtree of the root node, then process the root node, and at last process the right subtree of the root node. Noe let us understand tree traversal inorder with a simple example.
Numbers below each node denote the order in which the nodes are processed.
In the figure above, we first process the left subtree of root node 1. We call a recursive function for the left child of the root, which is 12, and then call recursion again for the left child of 12. We repeat this procedure until we are not on a leaf node. When we reach leaf node 5, there is no child; so, we process node 5 and return to its parent node 12.
We have already processed the left subtree of 12. So, we process node 12 and then call recursion on its right child and process its right subtree as we did the left. This is how we approach inorder tree traversal.
Algorithm and Pseudocode of Inorder Tree Traversal
Algorithm for Tree Traversal Inorder:
Inorder(root)
- Traverse the left sub-tree, (call inorder(left_child).
- Process the root node.
- Traverse the right subtree, (call inorder(right_child).
Psuedocode for Tree Traversal Inorder:
inorder(Node)
if (Node != null)
inorder(left_child)
Process the Node
inorder(right_child)
End if
End inorder
Application of Inorder Tree Traversal
Binary search tree or BST is a binary tree with a special property — for every node, the value stored in the left child (if it exists) is smaller than the value stored in the current node. Similarly, the value stored in the right child (if it exists) is greater than the value stored in the current node. For a BST, inorder tree traversal prints the nodes in non-decreasing order. A variation of inorder tree traversal can be used to obtain nodes from BST in non-increasing order.
Preorder Tree Traversal
Preorder traversal is another variant of DFS, where operations in the recursive function are similar to inorder tree traversal but in a different order.
In preorder traversal, we process the root node, then the left subtree of the root node, and at last process the right subtree of the root node.
In the figure above, we first process the root node 1. After processing the root node, we call a recursive function for the root child's left child, which is 12, and then we process node 12. After that, we call the recursive function on the left child of 12, which is 5, and process it. We repeat this procedure until we are not on a leaf node. There’s no child at leaf node 5. So, after processing node 5, we go back to its parent 12 and then process the right child (the same way we processed its left child).
Algorithm and Pseudocode Preorder Tree Traversal
Algorithm:
Preorder(root)
- Process the root node.
- Traverse the left sub-tree, (call preorder(root_left).
- Traverse the right subtree, (call preorder(root_right).
Pseudocode:
preorder(Node)
if (Node != null)
Process Node
preorder(left_child)
preorder(right_child)
End if
End preorder
Applications of Preorder Tree Traversal
We can create a copy of the tree using preorder traversal. Also, preorder traversal can be used to get the prefix expression of an expression.
Postorder Traversal
Postorder traversal is another variant of DFS. Here, operations in recursive function are similar to the inorder and preorder traversal but in a different order. In postorder traversal, we visit the left subtree nodes first and then traverse to the right subtree and visit nodes in it, and at last, we process the current node.
Similar to what we did in preorder and inorder tree traversals, in postorder traversal, we first process the left subtree, then the right subtree, and at last, the root node.
In the figure above, we first process the left subtree until we reach the leaf node. So, the first recursion will be called for the left child of node 1, i.e., for node 12. Then, we repeat this process until we are not on the leaf node. After reaching the leaf node, we process the leaf node, i.e., node 5. Next, we return to its parent, i.e., node 12. After processing the left subtree, we process the right subtree of 12 and repeat the same process as above. After that, we process node 12.
Algorithm and Pseudocode of Postorder Tree Traversal
Algorithm:
Postorder(root)
- Traverse the left sub-tree, (call postorder(root_left).
- Traverse the right subtree, (call postorder(root_right).
- Visit the root node.
Pseudocode:
postorder(Node)
if (Node != null)
postorder(left_child)
postorder(right_child)
Process Node
End if
End postorder
Applications of Postorder Tree Traversal
- Postorder traversal is used to delete the tree.
- Postorder traversal is also useful to get the postfix expression of an expression tree.
Levelorder Tree Traversal
Level-order traversal is another name of BFS to visit every node of a tree.
In level-order traversal, we traverse the tree level-wise, which means we visit all nodes in the current level and then move on to the next level. We use a queue data structure to implement the level order traversal where we visit/process a node and then pop the current node from the queue and push its left and right child in the queue.
This process continues till we process all the nodes in the tree.
Algorithm and Pseudocode for Level-order Tree Traversal
Algorithm:
Levelorder(node)
- Define an empty queue.
- Insert the starting node (root) into the queue.
- Pop the node from the queue and push all its children into the queue; repeat this process until the queue is not empty.
- Process the node popped in each iteration.
Pseudocode:
levelorder(root)
Queue q
q.push(root)
while ( ! q.empty() )
Node = q.pop()
Process Node
q.push(left_child)
q.push(right_child)
End while
End levelorder
Implementation of Tree Traversal: C++ Code
Following code is an example of how you can implement tree traversal in C++:
// Tree Traversals
#include <bits/stdc++.h>
using namespace std;
// Struct Node to represent the node of the tree
struct Node
{
// data will store the value of the node
int data;
// left and right are the pointers to the left and right child of current node
struct Node *left, *right;
// constructor to initialise the variables
Node(int data)
{
this->data = data;
// initially left and right will be NULL
left = right = NULL;
}
};
// Recursive function to print the preorder traversal of the tree
void PreorderTraversal(struct Node *node)
{
// base case if current node is NULL then we are done.
if (node == NULL)
return;
// printing the data in current node
cout << node->data << " ";
// calling recursion for left child to visit that first
PreorderTraversal(node->left);
// calling recursion for right child
PreorderTraversal(node->right);
}
// Recursive function to print the Postorder traversal of the tree
void PostorderTraversal(struct Node *node)
{
// base case if current node is NULL then we are done.
if (node == NULL)
return;
// calling recursion for left child
PostorderTraversal(node->left);
// calling recursion for right child
PostorderTraversal(node->right);
// printing the data in current node
cout << node->data << " ";
}
// Recursive function to print the Inorder tree traversal of the tree
void InorderTraversal(struct Node *node)
{
// base case if current node is NULL then we are done.
if (node == NULL)
return;
// calling recursion for left child
InorderTraversal(node->left);
// printing the data in current node
cout << node->data << " ";
// calling recursion for right child
InorderTraversal(node->right);
}
void LevelOrderTraversal(struct Node *node)
{
// declaring the empty queue
queue<Node *> q;
// pushing the starting node in queue
q.push(node);
// loop till queue is not empty
while (!q.empty())
{
Node *current = q.front();
q.pop();
// printing the data in current node
cout << current->data << " ";
// pushing the left and right childs provided they are not null
if (current->left != NULL)
q.push(current->left);
if (current->right != NULL)
q.push(current->right);
}
}
int main()
{
// creating the root node
struct Node *root = new Node(4);
// inserting the nodes in the tree
root->left = new Node(2);
root->right = new Node(6);
root->left->left = new Node(1);
root->right->left = new Node(5);
root->left->right = new Node(3);
root->right->right = new Node(7);
// calling traversal functions
cout << "Inorder tree traversal ";
InorderTraversal(root);
cout << "\n\n";
cout << "Preorder tree traversal ";
PreorderTraversal(root);
cout << "\n\n";
cout << "Postorder tree traversal ";
PostorderTraversal(root);
cout << "\n\n";
cout << "Level order tree traversal ";
LevelOrderTraversal(root);
cout << "\n\n";
}
Output:
Inorder tree traversal 1 2 3 4 5 6 7
Preorder tree traversal 4 2 1 3 6 5 7
Postorder tree traversal 1 3 2 5 7 6 4
Level order tree traversal 4 2 6 1 3 5
Time and Space Complexity of Tree Traversal Algorithms
Time complexity: In all the traversals, we visit every node once. It takes O(1) time to visit a node; hence, the time complexity of all the traversals will be O(n). Thus, the time complexity is O(n) for all traversals.
Auxiliary space:
- For preorder, postorder, and inorder tree traversals: If we consider the recursion stack, the space required is O(h), where h is the tree’s height. Else, it is O(1).
- For level-order traversal: Every node will be pushed in the queue exactly once. So, in the worst case, there can be O(n) nodes in the queue at a single moment. Hence, the space complexity is O(n).
Examples of Tech Interview Questions on Tree Traversals
- Print the bottom view of a binary tree
- Convert a binary tree to its sum tree (in place)
- Find whether a binary tree is a subtree of another binary tree
- Find the distance between given pairs of nodes in a binary tree
- Truncate a binary tree to remove nodes that lie on a path with sum less than “k”
- Count all subtrees with the same value of nodes in a binary tree
- Construct a binary tree in level-order and inorder tree traversal sequence
- Set “next” pointer to the inorder tree traversal successor of all nodes in a binary tree
- Find maximum path sum in a binary tree
- Check if a given binary tree is a binary search tree or not
- Find the vertical sum of a binary tree
Check out Interview Questions and Problems pages to learn more.
FAQs on Tree Traversals
Q1: How to apply any preorder, postorder, level-order, or inorder tree traversals to check whether the given binary tree is full or not?
A full binary tree is a tree having either zero or two children for each node. We can use any of the tree traversals: preorder, postorder, level-order, or inorder tree traversal. And while processing each node, we can check whether it has 0 or 2 children or not. This way, we can determine whether a given tree is a full binary tree or not.
Q2: Can we do inorder tree traversal without recursion?
Answer: Yes, we can do inorder tree traversal without recursion using the stack data structure. We create an empty stack, push the root node on it and then process the left subtree of the root node. To process the left subtree, we push the left child of the current node and update the current with its left child. We repeat this process until we are on the leaf node. Now, we pop the nodes one by one from the stack and process them, and update the current node with its right child. We repeat the same process until the stack is empty. Again, we follow the same process for the right subtree of the root node.
Pseudocode:
InorderTraversal
Create Empty Stack
While(true)
If (root is not NULL)
Stack.push(root)
root = root.left_child
End if
If (Stack if empty)
Break the loop
End if
root = Stack.pop()
// process the node root
root = root.right_child
End while
End InorderTraversal
Q3: What is the use of inorder tree traversal?
A variation of inorder tree traversal can be used to obtain nodes from BST in non-increasing order.
Q4: How do you do a tree traversal inorder?
We do a tree traversal inorder by traversing left, performing some operation on the current node, then traversing right.
Q5: What is true about doing tree traversal inorder?
Doing tree traversal inorder involves following the policy of Left-Root-Right.
Looking for a Tech Interview Prep Coach?
Interview Kickstart offers the best technical interview prep courses that make you a better engineer and help you nail tech interviews. As pioneers in the field of technical interview prep, we have trained thousands of software engineers to crack the toughest coding interviews and land jobs at their dream companies, such as Google, Facebook, Apple, Netflix, Amazon, and more!
For more information on what it takes to prepare for and succeed at FAANG tech interviews, sign up for our free webinar.
Given a Binary tree, Traverse it using DFS using recursion.
Unlike linear data structures (Array, Linked List, Queues, Stacks, etc) which have only one logical way to traverse them, trees can be traversed in different ways.
Generally, there are 2 widely used ways for traversing trees:
- DFS or Depth-First Search
- BFS or Breadth-First Search
What is a Depth-first search?
DFS (Depth-first search) is a technique used for traversing trees or graphs. Here backtracking is used for traversal. In this traversal first, the deepest node is visited and then backtracks to its parent node if no sibling of that node exists
DFS Traversal of a Graph vs Tree:
In the graph, there might be cycles and disconnectivity. Unlike the graph, the tree does not contain a cycle and are always connected. So DFS of a tree is relatively easier. We can simply begin from a node, then traverse its adjacent (or children) without caring about cycles. And if we begin from a single node (root), and traverse this way, it is guaranteed that we traverse the whole tree as there is no dis-connectivity,
Examples:
Input Tree:
Therefore, the Depth First Traversals of this Tree will be:
- Inorder: 4 2 5 1 3
- Preorder: 1 2 4 5 3
- Postorder: 4 5 2 3 1
Below are the Tree traversals through DFS using recursion:
1. Inorder Traversal (Practice):
Follow the below steps to solve the problem:
- Traverse the left subtree, i.e., call Inorder(left-subtree)
- Visit the root
- Traverse the right subtree, i.e., call Inorder(right-subtree)
Below is the implementation of the above algorithm:
C++
#include <bits/stdc++.h>
using
namespace
std;
struct
Node {
int
data;
struct
Node *left, *right;
Node(
int
data)
{
this
->data = data;
left = right = NULL;
}
};
void
printInorder(
struct
Node* node)
{
if
(node == NULL)
return
;
printInorder(node->left);
cout << node->data <<
" "
;
printInorder(node->right);
}
int
main()
{
struct
Node* root =
new
Node(1);
root->left =
new
Node(2);
root->right =
new
Node(3);
root->left->left =
new
Node(4);
root->left->right =
new
Node(5);
cout <<
"\nInorder traversal of binary tree is \n"
;
printInorder(root);
return
0;
}
C
#include <stdio.h>
#include <stdlib.h>
struct
node {
int
data;
struct
node* left;
struct
node* right;
};
struct
node* newNode(
int
data)
{
struct
node* node
= (
struct
node*)
malloc
(
sizeof
(
struct
node));
node->data = data;
node->left = NULL;
node->right = NULL;
return
(node);
}
void
printInorder(
struct
node* node)
{
if
(node == NULL)
return
;
printInorder(node->left);
printf
(
"%d "
, node->data);
printInorder(node->right);
}
int
main()
{
struct
node* root = newNode(1);
root->left = newNode(2);
root->right = newNode(3);
root->left->left = newNode(4);
root->left->right = newNode(5);
printf
(
"\nInorder traversal of binary tree is \n"
);
printInorder(root);
getchar
();
return
0;
}
Java
class
Node {
int
key;
Node left, right;
public
Node(
int
item)
{
key = item;
left = right =
null
;
}
}
class
BinaryTree {
Node root;
BinaryTree() { root =
null
; }
void
printInorder(Node node)
{
if
(node ==
null
)
return
;
printInorder(node.left);
System.out.print(node.key +
" "
);
printInorder(node.right);
}
void
printInorder() { printInorder(root); }
public
static
void
main(String[] args)
{
BinaryTree tree =
new
BinaryTree();
tree.root =
new
Node(
1
);
tree.root.left =
new
Node(
2
);
tree.root.right =
new
Node(
3
);
tree.root.left.left =
new
Node(
4
);
tree.root.left.right =
new
Node(
5
);
System.out.println(
"\nInorder traversal of binary tree is "
);
tree.printInorder();
}
}
Python
class
Node:
def
__init__(
self
, key):
self
.left
=
None
self
.right
=
None
self
.val
=
key
def
printInorder(root):
if
root:
printInorder(root.left)
print
(root.val),
printInorder(root.right)
root
=
Node(
1
)
root.left
=
Node(
2
)
root.right
=
Node(
3
)
root.left.left
=
Node(
4
)
root.left.right
=
Node(
5
)
print
"\nInorder traversal of binary tree is"
printInorder(root)
C#
using
System;
class
Node {
public
int
key;
public
Node left, right;
public
Node(
int
item)
{
key = item;
left = right =
null
;
}
}
public
class
BinaryTree {
Node root;
BinaryTree() { root =
null
; }
void
printInorder(Node node)
{
if
(node ==
null
)
return
;
printInorder(node.left);
317
0
0
All Comments (0)
Previous: Is post-order the same as DFS?
Next: Galvanized Steel T Posts
If you are interested in sending in a Guest Blogger Submission,welcome to write for us!
Comments