Given the root
of a binary tree, return the postorder traversal of its nodes' values.
Example 1:
Input: root = [1,null,2,3]
Output: [3,2,1]
Explanation:
Example 2:
Input: root = [1,2,3,4,5,null,8,null,null,6,7,9]
Output: [4,6,7,5,2,9,8,3,1]
Explanation:
Example 3:
Input: root = []
Output: []
Example 4:
Input: root = [1]
Output: [1]
Constraints:
[0, 100]
.-100 <= Node.val <= 100
Follow up: Recursive solution is trivial, could you do it iteratively?
#include <iostream>
#include <vector>
#include <stack>
using namespace std;
// Definition for a binary tree node.
struct TreeNode {
int val;
TreeNode *left;
TreeNode *right;
TreeNode() : val(0), left(nullptr), right(nullptr) {}
TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
};
// Recursive Solution
vector<int> postorderTraversalRecursive(TreeNode* root) {
vector<int> result;
if (root == nullptr) {
return result;
}
vector<int> leftSubtree = postorderTraversalRecursive(root->left);
result.insert(result.end(), leftSubtree.begin(), leftSubtree.end());
vector<int> rightSubtree = postorderTraversalRecursive(root->right);
result.insert(result.end(), rightSubtree.begin(), rightSubtree.end());
result.push_back(root->val);
return result;
}
// Iterative Solution using two stacks
vector<int> postorderTraversalIterative(TreeNode* root) {
vector<int> result;
if (root == nullptr) {
return result;
}
stack<TreeNode*> s1, s2;
s1.push(root);
while (!s1.empty()) {
TreeNode* node = s1.top();
s1.pop();
s2.push(node);
if (node->left) {
s1.push(node->left);
}
if (node->right) {
s1.push(node->right);
}
}
while (!s2.empty()) {
result.push_back(s2.top()->val);
s2.pop();
}
return result;
}
//Iterative Solution using one stack
vector<int> postorderTraversalIterativeSingleStack(TreeNode* root) {
vector<int> result;
if (!root) return result;
stack<TreeNode*> stack;
TreeNode* lastVisited = nullptr;
while (root || !stack.empty()) {
if (root) {
stack.push(root);
root = root->left;
} else {
TreeNode* topNode = stack.top();
// If right child exists and is not visited
if (topNode->right && topNode->right != lastVisited) {
root = topNode->right;
} else {
result.push_back(topNode->val);
lastVisited = topNode;
stack.pop();
}
}
}
return result;
}
int main() {
// Example usage:
TreeNode* root = new TreeNode(1);
root->right = new TreeNode(2);
root->right->left = new TreeNode(3);
cout << "Recursive Postorder Traversal: ";
vector<int> recursiveResult = postorderTraversalRecursive(root);
for (int val : recursiveResult) {
cout << val << " ";
}
cout << endl;
cout << "Iterative Postorder Traversal (Two Stacks): ";
vector<int> iterativeResult = postorderTraversalIterative(root);
for (int val : iterativeResult) {
cout << val << " ";
}
cout << endl;
cout << "Iterative Postorder Traversal (Single Stack): ";
vector<int> iterativeSingleStackResult = postorderTraversalIterativeSingleStack(root);
for (int val : iterativeSingleStackResult) {
cout << val << " ";
}
cout << endl;
// Clean up memory (important!)
delete root->right->left;
delete root->right;
delete root;
return 0;
}
Given a binary tree, the goal is to return the postorder traversal of its nodes' values. Postorder traversal means visiting the left subtree, then the right subtree, and finally the root node.
The recursive approach is straightforward and mirrors the definition of postorder traversal.
Algorithm:
nullptr
, return an empty vector.The iterative solution uses two stacks to simulate the recursive calls.
Algorithm:
s1
).s1
is not empty:
s1
and push it onto the second stack (s2
).s1
(if it exists).s1
(if it exists).s2
is not empty, pop nodes from s2
and add their values to the result vector. Since s2
contains the nodes in reverse postorder, popping them gives the correct postorder sequence.This iterative solution optimizes space by using only one stack.
Algorithm:
result
and pop off the stack), making note that you've visited it.