Iterative Binary Tree Traversals

April 18, 2022 7 min read

One of the common interview problems that frequently gets asked by interviewers is to write an inorder binary tree traversal algorithm. This problem may appear simple at first, but it is trickier than it appears. Although the recursive version is tidier, it hides the complexity that goes behind it. The recursive version may not always be the optimal solution to solve the problem. In this blog post, we will explore the iterative version of the inorder binary tree traversal algorithm.

Inorder Binary Search Tree Traversal

To start, let’s review the recursive version of the inorder binary search tree traversal algorithm.

inorderTraversal.cpp
Copy

_14
class Solution {
_14
public:
_14
void inorderTraversal(TreeNode* root) {
_14
if (!root) {
_14
return;
_14
}
_14
//Traverse to the left most node
_14
inorder(root -> left);
_14
//Magic goes here
_14
cout << root -> val << endl;
_14
//Go to the right node
_14
inorder(root -> right);
_14
}
_14
};

The inorder binary tree traversal algorithm requires that we print the leftmost node first and the rightmost node at the end. So for each node, we need to go as far down and left as possible.

The recursive version of the inorder traversal algorithm is simple to understand, but it has a drawback of using a stack that may cause a stack overflow error on large trees. Therefore, we will explore the iterative version of the inorder binary tree traversal algorithm using a stack.

inorderTraversal.cpp
Copy

_15
class Solution {
_15
public:
_15
void inorderTraversal(TreeNode* root) {
_15
if (!root) {
_15
return;
_15
}
_15
stack<TreeNode*> nodes;
_15
//Traverse to the left most node
_15
inorder(root -> left);
_15
//Magic goes here
_15
cout << root -> val << endl;
_15
//Go to the right node
_15
inorder(root -> right);
_15
}
_15
};

Here, we use a stack to store the left subtree nodes. We first traverse down to the leftmost node of the tree and push all the nodes along the way onto the stack. Once the leftmost node is found, we pop the node from the stack, process it, and then move to its right child. We repeat this process until the stack is empty.

inorderTraversal.cpp
Copy

_22
class Solution {
_22
public:
_22
void inorderTraversal(TreeNode* root) {
_22
if (!root) {
_22
return;
_22
}
_22
stack<TreeNode*> nodes;
_22
_22
//Traverse to the left most node
_22
while(root || !nodes.empty()) {
_22
while(root) {
_22
nodes.push(root);
_22
root = root->left;
_22
}
_22
_22
//Magic goes here
_22
cout << root -> val << endl;
_22
//Go to the right node
_22
inorder(root -> right);
_22
}
_22
}
_22
};

inorderTraversal.cpp
Copy

_23
class Solution {
_23
public:
_23
void inorderTraversal(TreeNode* root) {
_23
if (!root) {
_23
return;
_23
}
_23
stack<TreeNode*> nodes;
_23
_23
//Traverse to the left most node
_23
while(root || !nodes.empty()) {
_23
while(root) {
_23
nodes.push(root);
_23
root = root->left;
_23
}
_23
_23
root = nodes.top(); nodes.pop();
_23
//Magic goes here
_23
cout << root -> val << endl;
_23
//Go to the right node
_23
root = root->right;
_23
}
_23
}
_23
};

We can create a template for the inorder binary tree traversal algorithm that we can use to solve multiple leetcode problems.

To start, let’s review the recursive version of the inorder binary search tree traversal algorithm.

The inorder binary tree traversal algorithm requires that we print the leftmost node first and the rightmost node at the end. So for each node, we need to go as far down and left as possible.

The recursive version of the inorder traversal algorithm is simple to understand, but it has a drawback of using a stack that may cause a stack overflow error on large trees. Therefore, we will explore the iterative version of the inorder binary tree traversal algorithm using a stack.

Here, we use a stack to store the left subtree nodes. We first traverse down to the leftmost node of the tree and push all the nodes along the way onto the stack. Once the leftmost node is found, we pop the node from the stack, process it, and then move to its right child. We repeat this process until the stack is empty.

We can create a template for the inorder binary tree traversal algorithm that we can use to solve multiple leetcode problems.

inorderTraversal.cpp
CopyExpandClose

_14
class Solution {
_14
public:
_14
void inorderTraversal(TreeNode* root) {
_14
if (!root) {
_14
return;
_14
}
_14
//Traverse to the left most node
_14
inorder(root -> left);
_14
//Magic goes here
_14
cout << root -> val << endl;
_14
//Go to the right node
_14
inorder(root -> right);
_14
}
_14
};

inOrderTemplate.cpp
Copy

_22
class Solution {
_22
public:
_22
void inorderTraversal(TreeNode* root) {
_22
if (!root) {
_22
return;
_22
}
_22
stack<TreeNode*> nodes;
_22
_22
while(root || !nodes.empty()) {
_22
while(root) {
_22
nodes.push(root);
_22
root = root->left;
_22
}
_22
_22
root = nodes.top(); nodes.pop();
_22
//Magic goes here
_22
cout << root -> val << endl;
_22
_22
root = root->right;
_22
}
_22
}
_22
};

We can use this template to solve multiple leetcode problems by just adding specific code to handle each problem’s specific requirements.

inOrderTemplate.cpp
Solution.cpp
Copy

_24
class Solution {
_24
public:
_24
vector<int> inorderTraversal(TreeNode* root) {
_24
if (!root) {
_24
return {};
_24
}
_24
stack<TreeNode*> nodes;
_24
vector<int> result;
_24
_24
while(root || !nodes.empty()) {
_24
while(root) {
_24
nodes.push(root);
_24
root = root->left;
_24
}
_24
_24
root = nodes.top(); nodes.pop();
_24
_24
result.push_back(root->val);
_24
_24
root = root->right;
_24
}
_24
return result;
_24
}
_24
};

For leetcode problem Binary Tree Inorder Traversal, we need to return a list of node so rather than printing. This could be solved by storing the values in a list and returning it.

inOrderTemplate.cpp
Solution.cpp
Copy

_25
class Solution {
_25
public:
_25
bool isValidBST(TreeNode* root) {
_25
if (!root) {
_25
return true;
_25
}
_25
stack<TreeNode*> nodes;
_25
TreeNode* pre = nullptr;
_25
while(root || !nodes.empty()) {
_25
while(root) {
_25
nodes.push(root);
_25
root = root->left;
_25
}
_25
_25
root = nodes.top(); nodes.pop();
_25
//Magic goes here
_25
if(pre && root->val <= pre->val) return false;
_25
pre = root;
_25
_25
_25
root = root->right;
_25
}
_25
return true;
_25
}
_25
};

Similarly, in order to Validate Binary Search Tree could be solved by verifying if the in-order traversal is in ascending order

inOrderTemplate.cpp
Solution.cpp
Copy

_22
class Solution {
_22
public:
_22
int kthSmallest(TreeNode* root, int k) {
_22
stack<TreeNode*> nodes;
_22
_22
while(root || !nodes.empty()) {
_22
while(root) {
_22
nodes.push(root);
_22
root = root->left;
_22
}
_22
_22
root = nodes.top(); nodes.pop();
_22
//Magic goes here
_22
k--;
_22
if (k == 0) return root->val;
_22
_22
_22
root = root->right;
_22
}
_22
return -1;
_22
}
_22
};

Find Kth Smallest Element in a BST by simply breaking at kth element

inOrderTemplate.cpp
Solution.cpp
Copy

_21
class Solution {
_21
public:
_21
TreeNode* searchBST(TreeNode* root, int val) {
_21
stack<TreeNode*> nodes;
_21
_21
while(root || !nodes.empty()) {
_21
while(root) {
_21
nodes.push(root);
_21
root = root->left;
_21
}
_21
_21
root = nodes.top(); nodes.pop();
_21
//Magic goes here
_21
if (root->val == val) return root;
_21
_21
_21
root = root->right;
_21
}
_21
return NULL;
_21
}
_21
};

Search in a Binary Search Tree becomes much simpler and one needs to simply check for val you are looking for.

inOrderTemplate.cpp
Solution.cpp
Copy

_27
class Solution {
_27
public:
_27
TreeNode* increasingBST(TreeNode* root, int val) {
_27
TreeNode* head = new TreeNode(-1);
_27
TreeNode* prev = head;
_27
_27
stack<TreeNode*> nodes;
_27
_27
while(root || !nodes.empty()) {
_27
_27
while(root) {
_27
nodes.push(root);
_27
root = root->left;
_27
}
_27
_27
root = nodes.top(); nodes.pop();
_27
//Magic goes here
_27
prev->right = root;
_27
prev = prev->right;
_27
root->left = NULL;
_27
_27
_27
root = root->right;
_27
}
_27
return head->right;
_27
}
_27
};

Increasing Order Search Tree has similar intuition. Each time we meet a node, link it like a linked list using the right pointer. To facilitate the linking, create a dummy head

inOrderTemplate.cpp
Solution.cpp
Copy

_30
class Solution {
_30
public:
_30
void recoverTree(TreeNode* head) {
_30
TreeNode* first = NULL;
_30
TreeNode* second = NULL;
_30
TreeNode* root = head;
_30
TreeNode* prev = NULL;
_30
_30
stack<TreeNode*> nodes;
_30
_30
while(root || !nodes.empty()) {
_30
while(root) {
_30
nodes.push(root);
_30
root = root->left;
_30
}
_30
_30
root = nodes.top(); nodes.pop();
_30
//Magic goes here
_30
if (prev != NULL && prev->val > root->val) {
_30
if (first == NULL) {
_30
first = prev;
_30
}
_30
second = root;
_30
}
_30
prev = root;
_30
_30
root = root->right;
_30
}
_30
swap(first->val, second->val);
_30
};

For Recover Binary Search Tree, the question boils down to to find "2" elements in a given sorted arrangement , such that both of these elements violate the "sorted" order, and swap them back to their original places.

inOrderTemplate.cpp
Solution.cpp
Copy

_28
class Solution {
_28
public:
_28
TreeNode* convertBST(TreeNode* root, int val) {
_28
if (!root) return NULL;
_28
TreeNode* head = root;
_28
int sum = 0;
_28
int current_val;
_28
_28
stack<TreeNode*> nodes;
_28
_28
while(root || !nodes.empty()) {
_28
while(root) {
_28
nodes.push(root);
_28
root = root->right;
_28
}
_28
_28
root = nodes.top(); nodes.pop();
_28
//Magic goes here
_28
current_val = root->val;
_28
root->val = root->val + sum;
_28
sum += current_val;
_28
_28
_28
root = root->left;
_28
}
_28
return head;
_28
}
_28
};

For Convert BST to Greater Tree, The solution is the modification of inorder travel. Namely, travel right subtree, change the root value, and travel left subtree.

We can use this template to solve multiple leetcode problems by just adding specific code to handle each problem’s specific requirements.

For leetcode problem Binary Tree Inorder Traversal, we need to return a list of node so rather than printing. This could be solved by storing the values in a list and returning it.

Similarly, in order to Validate Binary Search Tree could be solved by verifying if the in-order traversal is in ascending order

Find Kth Smallest Element in a BST by simply breaking at kth element

Search in a Binary Search Tree becomes much simpler and one needs to simply check for val you are looking for.

Increasing Order Search Tree has similar intuition. Each time we meet a node, link it like a linked list using the right pointer. To facilitate the linking, create a dummy head

For Recover Binary Search Tree, the question boils down to to find "2" elements in a given sorted arrangement , such that both of these elements violate the "sorted" order, and swap them back to their original places.

For Convert BST to Greater Tree, The solution is the modification of inorder travel. Namely, travel right subtree, change the root value, and travel left subtree.

inOrderTemplate.cpp
CopyExpandClose

_22
class Solution {
_22
public:
_22
void inorderTraversal(TreeNode* root) {
_22
if (!root) {
_22
return;
_22
}
_22
stack<TreeNode*> nodes;
_22
_22
while(root || !nodes.empty()) {
_22
while(root) {
_22
nodes.push(root);
_22
root = root->left;
_22
}
_22
_22
root = nodes.top(); nodes.pop();
_22
//Magic goes here
_22
cout << root -> val << endl;
_22
_22
root = root->right;
_22
}
_22
}
_22
};

Once you have realized the pattern, you could see Binary Search Tree Iterator problem has the exact same structure

  1. Some initialization.
  2. A while-loop with a condition that tells whether there is more.
  3. The loop body gets the next value and does something with it.
BSTIterator.cpp
Copy

_33
class BSTIterator {
_33
stack<TreeNode*> nodes;
_33
TreeNode* head;
_33
int result;
_33
public:
_33
BSTIterator(TreeNode* root) {
_33
head = root;
_33
_33
while(head) {
_33
s.push(head);
_33
head = head->left;
_33
}
_33
}
_33
_33
int next() {
_33
head = s.top(); s.pop();
_33
result = head->val;
_33
if (head->right) {
_33
head = head->right;
_33
_33
while(head) {
_33
s.push(head);
_33
head = head->left;
_33
}
_33
}
_33
_33
return result;
_33
}
_33
_33
bool hasNext() {
_33
return !s.empty();
_33
}
_33
};

In this blog post, we’ve seen how to perform iterative inorder traversal of a binary tree. Although the recursive version is tidier, it hides the complexity that goes behind it. An iterative solution can help us solve multiple tree problems, and the same template could be used for multiple problems.


 Configure Nginx Proxy Manager with BitwardenBinary Search 

Want more?

Subscribe to get my latest content via email. I won’t send you spam, and you can unsubscribe at any time.