Given a binary tree root[]. Find the postorder traversal of the tree without using recursion. Return a list containing the postorder traversal of the tree, calculated without using recursion.
Examples:
Input:
Output: 4 5 2 3 1 Explanation: Postorder traversal (Left->Right->Root) of the tree is 4 5 2 3 1.
Input:
Output: 10 7 1 6 10 6 5 8 Explanation: Postorder traversal (Left->Right->Root) of the tree is 10 7 1 6 10 6 5 8.
[Two Stacks] Storing Reverse Postorder - O(n) Time and O(n) Space
The idea is to push Reverse Postorder to a stack. Once we have the reversed postorder in a stack, we just pop all items one by one from the stack and print them
How to get reversed postorder in a stack - the second stack is used for this purpose. For example, in the following tree, we need to get reverse of 1 3 2 5 4 (reverse of 4 5 2 3 1) in a stack.
If we take a closer look at reverse of postorder, we can observe that this sequence is very similar to the preorder traversal. The only difference is that the right child is visited before left child, and therefore the sequence is “root right left” instead of “root left right”. So, we do something like iterative preorder traversal with the following differences:
Instead of printing an item, we push it to a stack.
We push the left subtree before the right subtree..
Step 1: Create two empty stacks, stack1 and stack2.
Push the root into stack1.
Step 2: Process nodes using stack1.
Pop a node from stack1 and push it into stack2.
Push its left child and then its right child into stack1.
Step 3: Continue until stack1 becomes empty.
Each node is processed once and stored in stack2.
This gives stack2 the order Root → Right → Left.
Step 4: Process stack2.
Pop each node and add its value to the result.
Since stack2 follows LIFO, the order becomes Left → Right → Root.
Step 5: The result is the required postorder traversal.
Let us consider the following tree :
Step 1: Start with stack1 = [1] and stack2 = [].
Pop 1 from stack1 and push it into stack2.
Push left child 2, then right child 3 into stack1.
stack1: [2, 3] | stack2: [1]
Step 2: Process node 3.
Pop 3 from stack1 and push it into stack2.
3 has no children.
stack1: [2] | stack2: [1, 3]
Step 3: Process node 2.
Pop 2 from stack1 and push it into stack2.
Push left child 4, then right child 5 into stack1.
stack1: [4, 5] | stack2: [1, 3, 2]
Step 4: Process node 5.
Pop 5 from stack1 and push it into stack2.
5 has no children.
stack1: [4] | stack2: [1, 3, 2, 5]
Step 5: Process node 4.
Pop 4 from stack1 and push it into stack2.
4 has no children.
stack1: [] | stack2: [1, 3, 2, 5, 4]
Step 6: Now stack1 is empty, so process stack2.
Pop nodes from stack2: 4 → 5 → 2 → 3 → 1.
Result: 4 5 2 3 1
Final Postorder : 4 5 2 3 1
C++
// C++ program to o find the postorder // traversal using 2 Stacks#include<bits/stdc++.h>usingnamespacestd;classNode{public:intdata;Node*left;Node*right;Node(intx){data=x;left=right=nullptr;}};// Function to do post-order traversal// using two stacks iterativelyvector<int>postOrder(Node*root){vector<int>result;if(root==nullptr){returnresult;}// Create two stacksstack<Node*>stk1,stk2;// Push root to first stackstk1.push(root);Node*curr;// Run while first stack is not emptywhile(!stk1.empty()){// Pop from s1 and push it to s2curr=stk1.top();stk1.pop();stk2.push(curr);// Push left and right children of the// popped nodeif(curr->left){stk1.push(curr->left);}if(curr->right){stk1.push(curr->right);}}// Collect all elements from second stackwhile(!stk2.empty()){curr=stk2.top();stk2.pop();result.push_back(curr->data);}returnresult;}voidprintArray(constvector<int>&arr){for(intdata:arr){cout<<data<<" ";}cout<<endl;}intmain(){// Representation of input binary tree:// 1// / \ // 2 3// / \ // 4 5Node*root=newNode(1);root->left=newNode(2);root->right=newNode(3);root->left->left=newNode(4);root->left->right=newNode(5);vector<int>result=postOrder(root);printArray(result);return0;}
Java
// Java program to o find the postorder // traversal using 2 Stacksimportjava.util.ArrayList;importjava.util.Stack;classNode{intdata;Nodeleft,right;Node(intx){data=x;left=right=null;}}classGfG{// Function to do post-order traversal // using two stacksstaticArrayList<Integer>postOrder(Noderoot){ArrayList<Integer>result=newArrayList<>();if(root==null){returnresult;}// Create two stacksStack<Node>stk1=newStack<>();Stack<Node>stk2=newStack<>();// Push root to first stackstk1.push(root);Nodecurr;// Run while first stack is not emptywhile(!stk1.isEmpty()){// Pop from stk1 and push it to stk2curr=stk1.pop();stk2.push(curr);// Push left and right children of // the popped nodeif(curr.left!=null){stk1.push(curr.left);}if(curr.right!=null){stk1.push(curr.right);}}// Collect all elements from second stackwhile(!stk2.isEmpty()){curr=stk2.pop();result.add(curr.data);}returnresult;}staticvoidprintArray(ArrayList<Integer>arr){for(intdata:arr){System.out.print(data+" ");}System.out.println();}publicstaticvoidmain(String[]args){// Representation of input binary tree:// 1// / \// 2 3// / \// 4 5Noderoot=newNode(1);root.left=newNode(2);root.right=newNode(3);root.left.left=newNode(4);root.left.right=newNode(5);ArrayList<Integer>result=postOrder(root);printArray(result);}}
Python
# Python program to o find the postorder # traversal using 2 StacksclassNode:def__init__(self,data):self.data=dataself.left=Noneself.right=None# Function to do post-order traversal # using two stacksdefpostOrder(root):result=[]ifrootisNone:returnresult# Create two stacksstk1=[]stk2=[]# Push root to first stackstk1.append(root)# Run while first stack is not emptywhilestk1:# Pop from stk1 and push it to stk2curr=stk1.pop()stk2.append(curr)# Push left and right children of # the popped nodeifcurr.left:stk1.append(curr.left)ifcurr.right:stk1.append(curr.right)# Collect all elements from second stackwhilestk2:curr=stk2.pop()result.append(curr.data)returnresultdefprintArray(arr):print(" ".join(map(str,arr)))if__name__=="__main__":# Representation of input binary tree:# 1# / \# 2 3# / \# 4 5root=Node(1)root.left=Node(2)root.right=Node(3)root.left.left=Node(4)root.left.right=Node(5)result=postOrder(root)printArray(result)
C#
// C# program to o find the postorder // traversal using 2 StacksusingSystem;usingSystem.Collections.Generic;classNode{publicintdata;publicNodeleft,right;publicNode(intx){data=x;left=right=null;}}classGfG{// Function to do post-order traversal // using two stacksstaticList<int>postOrder(Noderoot){List<int>result=newList<int>();if(root==null){returnresult;}// Create two stacksStack<Node>stk1=newStack<Node>();Stack<Node>stk2=newStack<Node>();// Push root to first stackstk1.Push(root);// Run while first stack is not emptywhile(stk1.Count>0){// Pop from stk1 and push it to stk2Nodecurr=stk1.Pop();stk2.Push(curr);// Push left and right children of // the popped nodeif(curr.left!=null){stk1.Push(curr.left);}if(curr.right!=null){stk1.Push(curr.right);}}// Collect all elements from second stackwhile(stk2.Count>0){Nodecurr=stk2.Pop();result.Add(curr.data);}returnresult;}staticvoidprintArray(List<int>arr){foreach(intdatainarr){Console.Write(data+" ");}Console.WriteLine();}staticvoidMain(string[]args){// Representation of input binary tree:// 1// / \// 2 3// / \// 4 5Noderoot=newNode(1);root.left=newNode(2);root.right=newNode(3);root.left.left=newNode(4);root.left.right=newNode(5);List<int>result=postOrder(root);printArray(result);}}
JavaScript
// JavaScript program to find the postorder // traversal using 2 StacksclassNode{constructor(key){this.key=key;this.left=null;this.right=null;}}// Function to perform postorder traversal // using two stacksfunctionpostOrder(root){constans=[];if(!root)returnans;conststk1=[root];conststk2=[];// Loop while stk1 is not emptywhile(stk1.length>0){constnode=stk1.pop();// Push node's key to stk2stk2.push(node.key);// Push left and right children to stk1if(node.left)stk1.push(node.left);if(node.right)stk1.push(node.right);}// Collect nodes from s2 in postorderwhile(stk2.length>0){ans.push(stk2.pop());}returnans;}// Representation of input binary tree:// 1// / \// 2 3// / \// 4 5constroot=newNode(1);root.left=newNode(2);root.right=newNode(3);root.left.left=newNode(4);root.left.right=newNode(5);constresult=postOrder(root);console.log(result.join(' '));
Output
4 5 2 3 1
[Single Stack] Moving both Root and Right - O(n) Time and O(h) Space
The idea is to move down to leftmost node using left pointer. While moving down, push root and root's right child to stack. Once we reach leftmost node, print it if it doesn't have a right child. If it has a right child, then change root so that the right child is processed before.
Step 1: Create an empty stack.
Step 2: Go to the leftmost node.
If the current node has a right child, push the right child into the stack.
Push the current node into the stack.
Move to the left child.
Step 3: When there is no left child, pop a node from the stack.
If its right child is still waiting on the stack, process the right subtree first.
Otherwise, add the node to the result.
Step 4: Repeat until the stack is empty.
Let us consider the following tree :
Step 1: Start at 1.
Push its right child 3, then 1.
Move to left child 2.
Stack: 3, 1
Step 2: At 2.
Push its right child 5, then 2.
Move to left child 4.
Stack: 3, 1, 5, 2
Step 3: At 4.
Push 4 and move to NULL.
Pop 4 and add it to the result.
Result: 4
Stack: 3, 1, 5, 2
Step 4: Pop 2.
Its right child 5 is waiting on top, so process the right subtree.
[Single Stack] Tracking Last Visited Node - O(n) Time and O(n) Space
Use one stack to simulate recursion. Move left while pushing nodes onto the stack. When the left subtree is done, check the top node’s right child. If it is not visited, process the right subtree; otherwise, process the node itself.
Step 1: Create an empty stack and set lastVisited as NULL.
Step 2: Go to the leftmost node.
Push the current node into the stack.
Move to the left child.
Repeat until the current node becomes NULL.
Step 3: When the current node is NULL, check the top node of the stack.
If it has a right child that has not been visited, move to the right child.
Otherwise, add the node to the result, mark it as lastVisited, and pop it from the stack.
Step 4: Repeat the above steps until both the stack is empty and the current node is NULL.
Step 5: The result gives the nodes in Left -> Right -> Root order, which is the postorder traversal.
Let us consider the following tree :
Step 1: Start with an empty stack and lastVisited = NULL.
Push 1, 2, and 4 while moving to the leftmost node.
Current node becomes NULL.
Stack: 1, 2, 4
Step 2: Check the top node 4.
4 has no right child, so process 4.
Result: 4, lastVisited = 4
Stack: 1, 2
Step 3: Check the top node 2.
Its right child 5 is not visited, so move to 5.
Push 5 and move to NULL.
Stack: 1, 2, 5
Step 4: Check the top node 5.
5 has no right child, so process 5.
Result: 4, 5, lastVisited = 5
Stack: 1, 2
Step 5: Check 2 again.
Its right child 5 is already visited, so process 2.
Result: 4, 5, 2, lastVisited = 2
Stack: 1
Step 6: Check 1.
Its right child 3 is not visited, so move to 3 and process it.
Result: 4, 5, 2, 3, lastVisited = 3
Stack: 1
Step 7: Check 1 again.
Its right child 3 is already visited, so process 1.
Result: 4, 5, 2, 3, 1
Stack: empty.
Final Postorder : 4 5 2 3 1
C++
#include<iostream>#include<vector>#include<stack>#include<queue>#include<sstream>usingnamespacestd;structNode{intdata;Node*left;Node*right;Node(intval){data=val;left=nullptr;right=nullptr;}};vector<int>postOrder(Node*root){vector<int>res;if(!root)returnres;stack<Node*>s;Node*lastVisited=nullptr;while(!s.empty()||root){// Keep moving to the left // until we reach a nullif(root){s.push(root);root=root->left;}else{// Take out an item from stackNode*peekNode=s.top();// If the taken out item has a // right child and the right child// is not visited, move to the rightif(peekNode->right&&lastVisited!=peekNode->right){root=peekNode->right;// If there is no right child// or the right child is already// visited, then add peekNode to the// result and remove from the stack}else{res.push_back(peekNode->data);lastVisited=s.top();s.pop();}}}returnres;}// Driver program to test above functionsintmain(){Node*root=newNode(1);root->left=newNode(2);root->right=newNode(3);root->left->left=newNode(4);root->left->right=newNode(5);vector<int>res=postOrder(root);for(autoit:res)cout<<it<<" ";return0;}
classNode:def__init__(self,val):self.data=valself.left=Noneself.right=NonedefpostOrder(root):res=[]ifrootisNone:returnress=[]lastVisited=Nonewhilesorroot:ifroot:s.append(root)root=root.leftelse:peekNode=s[-1]ifpeekNode.rightandlastVisited!=peekNode.right:root=peekNode.rightelse:res.append(peekNode.data)lastVisited=s.pop()returnres# Driver program to test above functionsif__name__=='__main__':root=Node(1)root.left=Node(2)root.right=Node(3)root.left.left=Node(4)root.left.right=Node(5)res=postOrder(root)print(' '.join(map(str,res)),end='')
[Single Stack] Iterative Postorder Traversal - O(n) Time and O(n) Space
The main idea is to simulate the recursive postorder traversal using a stack. Along with each node, we store an extra field that tells us whether the node is being processed for its left child, right child, or itself.
0 : Left child needs to be processed 1 : Right child needs to be processed 2 : Node itself is ready to be added to the postorder traversal
Step 1: Initialize the stack
Create a stack that stores pairs of (node, state).
If the tree is not empty, push the root node with state 0.
Step 2: Process the top element
Pop the top pair (node, state) from the stack.
The state tells us what should be processed next for that node.
Step 3: Process according to the state
If state = 0:
Push (node, 1) back into the stack.
Push the left child as (node->left, 0) if it exists.
This ensures that the left subtree is processed before moving to the right subtree.
If state = 1:
Push (node, 2) back into the stack.
Push the right child as (node->right, 0) if it exists.
This ensures that the right subtree is processed before the node itself.
If state = 2:
The left and right subtrees have been processed.
Add node->data to the result.
Step 4: Repeat
Continue processing while the stack is not empty.
The nodes are added to the result in the order Left → Right → Root, which is the postorder traversal.
Let us consider the following tree :
Step 1: Start with the root
Push (1, 0) into the stack.
State 0 means the left subtree needs to be processed.
Stack: [(1, 0)]
Result: []
Step 2: Process node 1
Pop (1, 0).
Push (1, 1) back into the stack.
Push its left child (2, 0).
Stack: [(1, 1), (2, 0)]
Result: []
Step 3: Process node 2 and its left subtree
Pop (2, 0).
Push (2, 1) and then push its left child (4, 0).
Node 4 has no children, so add 4 to the result.
Then process the right child of 2 by pushing (2, 2) and (5, 0).
Node 5 has no children, so add 5 to the result.
Stack: [(1, 1), (2, 2)]
Result: [4, 5]
Step 4: Process node 2
Pop (2, 2).
Both its left and right subtrees are processed.
Add 2 to the result.
Stack: [(1, 1)]
Result: [4, 5, 2]
Step 5: Process node 1's right subtree
Pop (1, 1).
Push (1, 2) and then push its right child (3, 0).
Node 3 has no children, so add 3 to the result.
Stack: [(1, 2)]
Result: [4, 5, 2, 3]
Step 6: Process node 1
Pop (1, 2).
Both its left and right subtrees are processed.
Add 1 to the result.
Stack: []
Result: [4, 5, 2, 3, 1]
Therefore, the postorder traversal is [4, 5, 2, 3, 1].
C++
#include<bits/stdc++.h>usingnamespacestd;structNode{intdata;Node*left;Node*right;Node(intval){data=val;left=right=NULL;}};vector<int>postOrder(Node*root){vector<int>ans;if(root==NULL)returnans;// Stack stores the node along with its current state.stack<pair<Node*,int>>st;st.push({root,0});while(!st.empty()){auto[node,state]=st.top();st.pop();// State 0: Process the left subtree.if(state==0){st.push({node,1});if(node->left)st.push({node->left,0});}// State 1: Process the right subtree.elseif(state==1){st.push({node,2});if(node->right)st.push({node->right,0});}// State 2: Both subtrees are processed, so add the node.else{ans.push_back(node->data);}}returnans;}intmain(){Node*root=newNode(1);root->left=newNode(2);root->right=newNode(3);root->left->left=newNode(4);root->left->right=newNode(5);vector<int>ans=postOrder(root);for(intx:ans)cout<<x<<" ";return0;}
Java
importjava.util.ArrayList;importjava.util.Stack;publicclassGFG{staticclassNodeState{Nodenode;intstate;NodeState(Nodenode,intstate){this.node=node;this.state=state;}}staticArrayList<Integer>postOrder(Noderoot){ArrayList<Integer>ans=newArrayList<>();if(root==null)returnans;// Stack stores each node along with its current state.Stack<NodeState>st=newStack<>();st.push(newNodeState(root,0));while(!st.empty()){NodeStatecurrent=st.pop();Nodenode=current.node;intstate=current.state;// State 0: Process the left subtree.if(state==0){st.push(newNodeState(node,1));if(node.left!=null)st.push(newNodeState(node.left,0));}// State 1: Process the right subtree.elseif(state==1){st.push(newNodeState(node,2));if(node.right!=null)st.push(newNodeState(node.right,0));}// State 2: Both subtrees are processed, so add the node.else{ans.add(node.data);}}returnans;}publicstaticvoidmain(String[]args){Noderoot=newNode(1);root.left=newNode(2);root.right=newNode(3);root.left.left=newNode(4);root.left.right=newNode(5);ArrayList<Integer>ans=postOrder(root);for(intx:ans)System.out.print(x+" ");}}
Python
defpostOrder(root):ans=[]ifrootisNone:returnans# Stack stores the node along with its current state.stack=[(root,0)]whilestack:node,state=stack.pop()# State 0: Process the left subtree.ifstate==0:stack.append((node,1))ifnode.left:stack.append((node.left,0))# State 1: Process the right subtree.elifstate==1:stack.append((node,2))ifnode.right:stack.append((node.right,0))# State 2: Both subtrees are processed, so add the node.else:ans.append(node.data)returnansif__name__=="__main__":root=Node(1)root.left=Node(2)root.right=Node(3)root.left.left=Node(4)root.left.right=Node(5)print(*postOrder(root))
C#
usingSystem;usingSystem.Collections.Generic;classNodeState{publicNodenode;publicintstate;publicNodeState(Nodenode,intstate){this.node=node;this.state=state;}}publicclassGFG{staticList<int>postOrder(Noderoot){List<int>ans=newList<int>();if(root==null)returnans;// Stack stores the node along with its current state.Stack<NodeState>st=newStack<NodeState>();st.Push(newNodeState(root,0));while(st.Count>0){NodeStatecurrent=st.Pop();Nodenode=current.node;intstate=current.state;// State 0: Process the left subtree.if(state==0){st.Push(newNodeState(node,1));if(node.left!=null)st.Push(newNodeState(node.left,0));}// State 1: Process the right subtree.elseif(state==1){st.Push(newNodeState(node,2));if(node.right!=null)st.Push(newNodeState(node.right,0));}// State 2: Both subtrees are processed, so add the node.else{ans.Add(node.data);}}returnans;}publicstaticvoidMain(){Noderoot=newNode(1);root.left=newNode(2);root.right=newNode(3);root.left.left=newNode(4);root.left.right=newNode(5);List<int>ans=postOrder(root);foreach(intxinans)Console.Write(x+" ");}}