Preorder, Inorder, and Postorder Traversal: Three Orders, One Rule

- Preorder (root → left → right) visits the root first, making it the right choice for tree serialization, cloning, and any problem that passes state downward.
- Inorder traversal of a BST always produces sorted output, which unlocks kth-smallest, BST validation, and range queries in a single linear pass.
- Postorder (left → right → root) processes children before the parent, making it correct for tree deletion, height computation, and bottom-up DP.
- The only thing that moves between the three traversals is the root — before, between, or after the recursive calls; left always precedes right.
- Time complexity is O(n) for all three; space is O(h), where h is O(log n) for balanced trees and O(n) worst case for degenerate ones.
- The pattern shortcut: BST + "sorted"/"kth" = inorder; "aggregate upward" = postorder; serialize or reconstruct = preorder.

If you've spent time trying to memorize which traversal is which, here's the unlock: the names are literally telling you the answer. "Pre" means before. "In" means between. "Post" means after. They're telling you exactly where the root lands relative to its children.
That's the whole model. Every implementation detail follows from that one rule.
Preorder, Inorder, and Postorder on the Same Tree
Tracing the same example through all three is the fastest way to see how they differ:
1
/ \
2 3
/ \
4 5
Node 1 is the root. Node 2 has two children. Node 3 is a leaf.

Preorder: Root Goes First
Preorder follows: root → left subtree → right subtree.
Trace it:
- Visit 1 (root)
- Go left: visit 2, then visit 4
- Back up to 2, go right: visit 5
- Back up to 1, go right: visit 3
Result: 1, 2, 4, 5, 3
The root always lands first. That's the pre. Simple enough that you'll feel slightly embarrassed it ever confused you.
def preorder(node): if node is None: return print(node.val) preorder(node.left) preorder(node.right)
function preorder(node: TreeNode | null): void { if (node === null) return; console.log(node.val); preorder(node.left); preorder(node.right); }
Preorder shows up whenever you need to process a parent before its children. Tree serialization is the clearest example: encode the root first so you can reconstruct the tree later, knowing where to re-attach the subtrees. Cloning a tree is the same idea. Create the root, then recursively create left and right.
Inorder: Root Goes in the Middle
Inorder follows: left subtree → root → right subtree.
Trace it:
- Go as far left as possible: visit 4
- Back up to 2: visit 2
- Go right from 2: visit 5
- Back up to 1: visit 1
- Go right: visit 3
Result: 4, 2, 5, 1, 3
def inorder(node): if node is None: return inorder(node.left) print(node.val) inorder(node.right)
function inorder(node: TreeNode | null): void { if (node === null) return; inorder(node.left); console.log(node.val); inorder(node.right); }
Inorder traversal of a binary search tree always produces a sorted sequence. This is the single most important property to know for interviews.
It falls directly from the BST invariant. Every left descendant is smaller than the node, every right descendant is larger. Inorder visits left first, then the node, then right. Smallest to largest, every time. No bubble sort required.

Inorder on a BST sorts in O(n). Your interviewer does not want to hear about bubble sort.
What this unlocks:
- Kth smallest element in a BST (LeetCode 230): run inorder, count to k.
- Validate a BST (LeetCode 98): run inorder, check that each value is strictly greater than the previous.
- Convert BST to sorted list: inorder gives you the elements in order; just collect them.
If a problem gives you a BST and asks for anything sorted, inorder is almost always the move.
Postorder: Root Goes Last
Postorder follows: left subtree → right subtree → root.
Trace it:
- Go far left: visit 4
- Back up to 2, go right: visit 5
- Back up to 2: visit 2
- Back up to 1, go right: visit 3
- Back up to 1: visit 1
Result: 4, 5, 2, 3, 1
The root always lands last. That's the post.
def postorder(node): if node is None: return postorder(node.left) postorder(node.right) print(node.val)
function postorder(node: TreeNode | null): void { if (node === null) return; postorder(node.left); postorder(node.right); console.log(node.val); }
Postorder shows up whenever a node's answer depends on combining results from both subtrees. You can't report to the parent until you've heard back from both children. Deleting a tree requires postorder: free all descendants before freeing the node, or you lose the pointers. Computing directory sizes works the same way: sum subdirectories first, then add the directory itself.
The most interview-relevant version: diameter of binary tree (LeetCode 543). The diameter through any node is left_height + right_height. You need both subtree heights before you can answer for the current node. That's a postorder dependency, even if you never write the word "postorder" in your code.
Most bottom-up tree DP is postorder thinking in disguise. Any time you compute something at a leaf, pass it upward, and combine at each parent, that's postorder. Recognize the structure and you can skip the "which traversal?" deliberation entirely.
The One Rule
The name tells you where the root falls relative to the children:
| Traversal | Order | Root Position |
|---|---|---|
| Preorder | Root → Left → Right | Before (prefix) |
| Inorder | Left → Root → Right | In the middle |
| Postorder | Left → Right → Root | After (suffix) |
Left always comes before Right in all three. The only thing that moves is the Root. If you can remember that, you can reconstruct any traversal order under pressure without memorizing three separate patterns.
O(n) Time. Space Depends on the Tree.
All three traversals visit every node exactly once. Time complexity is O(n) for all three, always.
Space is where it gets interesting. Recursive implementations use the call stack, and the stack depth equals tree height h.
- Balanced tree: h = O(log n), so space = O(log n)
- Skewed tree (each node has one child): h = O(n), so space = O(n)
Say O(h) in an interview, then immediately clarify: h is O(log n) for a balanced tree and O(n) worst case for a degenerate one. That distinction signals you understand the dependency on tree shape, not just the formula.
All three can also be implemented iteratively using an explicit stack on the heap. Same asymptotic complexity, but you avoid call stack overflow on pathologically deep trees.
Pattern Recognition: Which Traversal, When
Preorder for:
- Tree serialization and deserialization (encode root first to reconstruct later)
- Building a copy of a tree
- Problems where each node needs context from its ancestors (pass state downward)
Inorder for:
- Any BST problem involving sorted order: kth smallest, range queries, BST validation
- Recovering a BST from two swapped nodes
- Converting a BST to a doubly linked list
Postorder for:
- Tree deletion or cleanup
- Computing any property from children upward: height, diameter, path sum, max path
- Bottom-up DP on trees (very common in medium and hard problems)
The practical shortcut: BST + "sorted" or "kth" = inorder. General binary tree + "aggregate upward" = postorder. Reconstruct or serialize = preorder. See binary tree interview problems for concrete examples of each pattern.
One Recursion, Three Positions
All three traversals share the same recursion skeleton: handle the current node, recurse left, recurse right. The only difference is where in that sequence you do your actual work.
Move print(node.val) to the top and you get preorder. Put it between the recursive calls and you get inorder. Put it at the bottom and you get postorder. One line of code moves three inches and the entire behavior changes.
That's also why iterative implementations are harder than they look. A simulated stack doesn't have natural "before," "between," and "after" positions the way function calls do. You have to manually track where you are in the sequence when you return to a node. Iterative inorder is the most commonly tested. Iterative postorder is the trickiest to get right, and it will make you feel some things.

Iterative postorder is the one traversal that breaks you before it makes you.
The iterative preorder, iterative inorder, and iterative postorder implementations each have their own write-up if you want the full breakdown.
If you want to practice verbalizing this reasoning under pressure, not just implementing the traversal but explaining the right choice to an interviewer in real time, SpaceComplexity runs voice-based mock interviews where you talk through your tree traversal decisions and get rubric feedback on whether your reasoning was communicated clearly, not just whether your code was correct.
Further Reading
- Wikipedia: Tree traversal, formal definitions, non-recursive approaches, and level-order
- LeetCode 144: Binary Tree Preorder Traversal
- LeetCode 94: Binary Tree Inorder Traversal
- LeetCode 145: Binary Tree Postorder Traversal
- GeeksforGeeks: Tree Traversals, Inorder, Preorder and Postorder, additional diagrams and worked examples