We need to traverse a binary tree in postorder, which means: visit the left subtree first, then the right subtree, then the current node. This is the opposite of preorder (root, left, right) and different from inorder (left, root, right).
The recursive solution follows directly from this definition. The interesting part is the iterative version. Postorder is the hardest of the three traversals to do without recursion, because the root must be emitted last but is the first node reached while descending. An iterative solution has to return to each node after both of its subtrees are finished.
One relationship makes this manageable: postorder (left, right, root) is the reverse of a root-right-left traversal, which reduces iterative postorder to a small variation on iterative preorder.
Number of nodes in range [0, 100] → Small input, so performance is not the concern. The problem is about implementing the traversal correctly, especially without recursion.Postorder traversal is defined recursively: visit the left subtree, visit the right subtree, then visit the root. The code follows the definition: recurse left, recurse right, append the current node's value.
The recursion solves the "come back to the root after both subtrees" problem through the call stack. When the left recursive call returns, the right one starts. When the right one returns, the current node is appended. The call stack does all the bookkeeping.
postorder(node):node is null, return. This also covers an empty tree.node.val to the result.postorder(root) and return the result.The recursive solution is optimal in time, but it relies on the call stack, and a deep enough tree overflows it. The next two approaches manage an explicit stack instead.
A preorder-style traversal that visits the root, then the right child, then the left child produces the sequence root, right, left. Reversed, that sequence is left, right, root, which is postorder.
This sidesteps the hard question of deciding when a node's subtrees are finished. A root-right-left traversal is as easy to write with a stack as ordinary preorder, and one reversal at the end converts its output to postorder.
We push left before right. Since a stack is LIFO, the right child gets popped first. This gives us root-right-left traversal order. Reversing produces left-right-root, which is postorder.
The reversal produces the correct list, but the nodes are processed in root-right-left order and only rearranged at the end. If something had to happen at each node in postorder position (freeing the node, computing a subtree aggregate), this ordering would be wrong. The final approach visits each node in true postorder position with a single stack and no reversal.
This approach reproduces what the recursion does, without the reversal. At each node, the left subtree must be processed, then the right subtree, then the node itself, but a stack-based descent reaches the node before either subtree. The node has to stay on the stack until both subtrees are done.
A previous pointer that tracks the last node added to the result resolves this. When we peek at the top of the stack, its left subtree is already finished (we only peek after descending as far left as possible). If its right child is null or equals previous, the right subtree is also finished, so the node can be popped and processed. Otherwise the traversal moves into the right child.
In the recursive version, a node's value is appended when the second recursive call returns. The previous pointer recreates that return signal: in postorder, the node processed immediately before any node with a right subtree is the last node of that right subtree, which is the right child itself. So previous == top.right holds exactly when the right subtree has just finished. The comparison must be by reference, not value; a tree with duplicate values would otherwise trigger false matches.
Setting current = null after a pop also matters. Without it, the outer loop would descend into the popped node's left subtree again. A null current skips the descent and goes straight to peeking the next node on the stack.
current = root and previous = null.current is not null or the stack is not empty:current is not null, push current onto the stack and move to current.left.previous (right subtree is done):previous = node, and set current = null.current = top.right.An empty tree never enters the loop, so no separate null check is needed.