Topics › Binary Trees › Traversals
Preorder Traversal
LeetCode ↗ Java source ↗ Edit this article ↗
Jump to code:
Problem
Given the root of a binary tree, return the values of its nodes in preorder. Preorder means that every node is listed before anything below it: first the node, then its entire left subtree in preorder, then its entire right subtree in preorder. The tree may be empty and values may repeat.
Constraints (LeetCode 144): between 0 and 100 nodes, values in [-100, 100]. The Java file also runs a 5000-node chain and a 100000-node tree.
Example 1
1
/ \
2 3
/ \ \
4 5 6
answer = [1, 2, 4, 5, 3, 6]
1 comes first. Then the whole left subtree rooted at 2 is listed (2, 4, 5) before the right subtree rooted at 3 (3, 6).
Example 2
root = [1, null, 2, 3] // 1 has a right child 2, and 2 has a left child 3
answer = [1, 2, 3]
1, then its right subtree: 2 first, then 2’s left child 3.
Preorder is the natural order whenever a parent must be handled before its children: copying a tree top-down, printing a directory listing, serializing a tree so it can be rebuilt (the first value read back is always the root), and rebuilding a tree from its preorder and inorder sequences.
Approach 1: Recursion
Intuition. Translate the definition directly: “preorder of a tree = the root, then preorder of the left subtree, then preorder of the right subtree”. The call stack remembers, for every node on the current path, that its right subtree still has to be visited once the left one returns.
Algorithm.
- If the node is
null, return. - Append the node’s value.
- Recurse into the left child.
- Recurse into the right child.
static List<Integer> recursive(TreeNode root) {
List<Integer> out = new ArrayList<>();
preorder(root, out);
return out;
}
static void preorder(TreeNode node, List<Integer> out) {
if (node == null) return;
out.add(node.val); // 1. the node itself, before anything below it
preorder(node.left, out); // 2. its whole left subtree
preorder(node.right, out); // 3. then its whole right subtree
}
Complexity. Time O(n): each node is entered once, and each of the n + 1 null children costs one extra constant-time call. Space O(h) for the call stack, where h is the tree height: O(log n) when balanced, O(n) for a chain. On a very deep chain (around 10^5 nodes) the default Java stack can overflow, which is why the iterative form is worth knowing.
Approach 2: Iterative with an explicit stack
Intuition. Preorder is the easiest traversal to make iterative because a node is emitted the moment it is reached; nothing has to stay “pending” until later, unlike inorder. What we do need to remember is the work still waiting: after emitting a node we must handle its left subtree, then its right subtree. A stack is last-in-first-out, so we push the right child first and the left child second. The left child is then on top and gets processed next.
Why does the whole left subtree finish before the right child is popped? The right child sits directly below the left child in the stack. Everything pushed while the left subtree is being processed goes on top of the right child, so the right child cannot surface until every node of the left subtree has been popped. That is exactly “left subtree entirely before right subtree”.
Algorithm.
- If the root is
null, return an empty list. - Push the root.
- While the stack is not empty:
- Pop a node and append its value.
- Push its right child if present, then its left child if present.
- Return the list.
static List<Integer> iterative(TreeNode root) {
List<Integer> out = new ArrayList<>();
if (root == null) return out;
Deque<TreeNode> stack = new ArrayDeque<>();
stack.push(root);
while (!stack.isEmpty()) {
TreeNode node = stack.pop();
out.add(node.val);
if (node.right != null) stack.push(node.right); // LIFO: pushed first, processed last
if (node.left != null) stack.push(node.left);
}
return out;
}
Dry run on Example 1 (stack shown bottom to top):
| step | popped | output so far | pushed (right, then left) | stack after |
|---|---|---|---|---|
| 1 | 1 | 1 | 3, 2 | [3, 2] |
| 2 | 2 | 1, 2 | 5, 4 | [3, 5, 4] |
| 3 | 4 | 1, 2, 4 | (none) | [3, 5] |
| 4 | 5 | 1, 2, 4, 5 | (none) | [3] |
| 5 | 3 | 1, 2, 4, 5, 3 | 6 | [6] |
| 6 | 6 | 1, 2, 4, 5, 3, 6 | (none) | [] |
Complexity. Time O(n): each node is pushed and popped once. Space O(h): at any moment the stack holds the node being expanded plus at most one waiting right child for each node on the current path, so its size is bounded by the height plus one. For a balanced tree that is O(log n). A chain in either direction keeps the stack at size one, because each node has only one child to push. The stack grows only when many nodes on the current path each leave a right child waiting, and there can be at most h of those.
There is a second iterative style that mirrors the inorder loop: walk down the left spine, recording each node as you push it, then pop and move to the right child. It produces the same order and the same complexity. The version above is shorter and is the one most people remember.
If you need O(1) extra space, Morris preorder traversal threads the tree temporarily instead of using a stack.
Edge cases and pitfalls
- Empty tree. Pushing
nullinto anArrayDequethrowsNullPointerException, so the iterative method returns early whenroot == null. The recursive method handles it in its base case. - Push order. Pushing left before right produces “node, right, left”, which is a mirrored preorder (and is a stepping stone toward the two-stack postorder trick), not preorder.
- Null children. Only push children that exist. Besides avoiding the
NullPointerException, it keeps the stack small. - Duplicates and negatives. Values are never compared, so nothing special is needed. The tests include
[0, -5, 5, -5, 0]. - Deep trees. The tests run a 5000-node right chain through both methods. For trees whose height approaches
10^5, prefer the iterative or Morris version.
Related problems
- Inorder Traversal uses the same two techniques, but the node waits for its left subtree.
- Morris Preorder Traversal produces preorder with
O(1)extra space. - Postorder Traversal records the node after both subtrees.
- Pre, Post, Inorder in one traversal computes all three orders in a single pass.
- Construct a BT from Preorder and Inorder rebuilds a tree using the fact that preorder starts with the root.
- Serialize and De-serialize BT commonly uses a preorder walk with null markers.