Traversal methods
The ways to visit every node of a binary tree: preorder, inorder, postorder, recursive depth-first search, iterative traversals with an explicit stack and level-order breadth-first search.
Learning goals
- Produce preorder, inorder and postorder sequences by hand and in code
- Explain how the call stack drives depth-first search
- Rewrite each depth-first traversal with an explicit stack
- Traverse by level with a queue
Prerequisites
Almost every tree algorithm is a traversal with a small job attached to the visit. Knowing exactly when each node is visited, and what the stack or queue holds at that moment, is the whole skill.
Preorder
**Preorder** visits the node, then its left subtree, then its right subtree. The root always comes first, so a preorder sequence is a natural way to copy or serialise a tree: reading it back creates every parent before its children.
On the tree “1 2 3 4 5 # 6” (root 1 with children 2 and 3; 2 has children 4 and 5; 3 has only a right child 6) preorder is [1, 2, 4, 5, 3, 6]. Step through the “Preorder” preset: each node is output on the way *down*, before either subtree is touched.
1static void preorder(TreeNode n, List<Integer> out) {2if (n == null) return;3out.add(n.val); // visit first4preorder(n.left, out);5preorder(n.right, out);6}
Best
O(n)
Average
O(n)
Worst
O(n)
Space
O(h) call stack, h = height
Binary tree traversals: preorder, inorder, postorder and level order
Interactive · edit the inputbinary tree · 6 nodes
output
Preorder traversal of a tree with 6 nodes. The recursion's call stack remembers the path back to the root.
1static void preorder(TreeNode n, List<Integer> out) {2if (n == null) return; // empty subtree: nothing to visit3out.add(n.val); // visit the node first4preorder(n.left, out);5preorder(n.right, out);6}7static void inorder(TreeNode n, List<Integer> out) {8if (n == null) return;9inorder(n.left, out);10out.add(n.val); // visit between the two subtrees11inorder(n.right, out);12}13static void postorder(TreeNode n, List<Integer> out) {14if (n == null) return;15postorder(n.left, out);16postorder(n.right, out);17out.add(n.val); // visit after both subtrees18}19static List<Integer> levelOrder(TreeNode root) {20List<Integer> out = new ArrayList<>();21Deque<TreeNode> queue = new ArrayDeque<>();22if (root != null) queue.add(root);23while (!queue.isEmpty()) {24TreeNode n = queue.poll(); // oldest node first25out.add(n.val);26if (n.left != null) queue.add(n.left);27if (n.right != null) queue.add(n.right);28}29return out;30}
Live state
visited
0
Execution trace (dry run table)Show 21 stepsHide
| Step | Line | State | What happens |
|---|---|---|---|
| 1 | L1 | visited=0 | Preorder traversal of a tree with 6 nodes. The recursion's call stack remembers the path back to the root. |
| 2 | L1 | visited=0 stack depth=1 | Call preorder(1), the root. |
| 3 | L3 | visited=1 stack depth=1 | Visit 1: before either subtree. |
| 4 | L1 | visited=1 stack depth=2 | Call preorder(2), depth 1. |
| 5 | L3 | visited=2 stack depth=2 | Visit 2: before either subtree. |
| 6 | L1 | visited=2 stack depth=3 | Call preorder(4), depth 2. |
| 7 | L3 | visited=3 stack depth=3 | Visit 4: before either subtree. |
| 8 | L4 | visited=3 stack depth=3 | The left child of 4 is empty, so that call returns at once. |
| 9 | L5 | visited=3 stack depth=3 | The right child of 4 is empty, so that call returns at once. |
| 10 | L1 | visited=3 stack depth=3 | Call preorder(5), depth 2. |
| 11 | L3 | visited=4 stack depth=3 | Visit 5: before either subtree. |
| 12 | L4 | visited=4 stack depth=3 | The left child of 5 is empty, so that call returns at once. |
| 13 | L5 | visited=4 stack depth=3 | The right child of 5 is empty, so that call returns at once. |
| 14 | L1 | visited=4 stack depth=2 | Call preorder(3), depth 1. |
| 15 | L3 | visited=5 stack depth=2 | Visit 3: before either subtree. |
| 16 | L4 | visited=5 stack depth=2 | The left child of 3 is empty, so that call returns at once. |
| 17 | L1 | visited=5 stack depth=3 | Call preorder(6), depth 2. |
| 18 | L3 | visited=6 stack depth=3 | Visit 6: before either subtree. |
| 19 | L4 | visited=6 stack depth=3 | The left child of 6 is empty, so that call returns at once. |
| 20 | L5 | visited=6 stack depth=3 | The right child of 6 is empty, so that call returns at once. |
| 21 | L1 | visited=6 | Preorder: [1, 2, 4, 5, 3, 6]. |
Inorder
**Inorder** visits the left subtree, then the node, then the right subtree. On a binary search tree this is the keys in **sorted order**, the single most useful fact about BSTs, used in the next chapter for validation, ranking and range queries.
The same tree gives [4, 2, 5, 1, 3, 6]. A node is output only after everything to its left is done; in the “Inorder” preset you can see node 1 wait until the whole left subtree (4, 2, 5) has been emitted.
1static void inorder(TreeNode n, List<Integer> out) {2if (n == null) return;3inorder(n.left, out);4out.add(n.val); // visit between the subtrees5inorder(n.right, out);6}
Best
O(n)
Average
O(n)
Worst
O(n)
Space
O(h) call stack
Binary tree traversals: preorder, inorder, postorder and level order
Interactive · edit the inputbinary tree · 6 nodes
output
Preorder traversal of a tree with 6 nodes. The recursion's call stack remembers the path back to the root.
1static void preorder(TreeNode n, List<Integer> out) {2if (n == null) return; // empty subtree: nothing to visit3out.add(n.val); // visit the node first4preorder(n.left, out);5preorder(n.right, out);6}7static void inorder(TreeNode n, List<Integer> out) {8if (n == null) return;9inorder(n.left, out);10out.add(n.val); // visit between the two subtrees11inorder(n.right, out);12}13static void postorder(TreeNode n, List<Integer> out) {14if (n == null) return;15postorder(n.left, out);16postorder(n.right, out);17out.add(n.val); // visit after both subtrees18}19static List<Integer> levelOrder(TreeNode root) {20List<Integer> out = new ArrayList<>();21Deque<TreeNode> queue = new ArrayDeque<>();22if (root != null) queue.add(root);23while (!queue.isEmpty()) {24TreeNode n = queue.poll(); // oldest node first25out.add(n.val);26if (n.left != null) queue.add(n.left);27if (n.right != null) queue.add(n.right);28}29return out;30}
Live state
visited
0
Execution trace (dry run table)Show 21 stepsHide
| Step | Line | State | What happens |
|---|---|---|---|
| 1 | L1 | visited=0 | Preorder traversal of a tree with 6 nodes. The recursion's call stack remembers the path back to the root. |
| 2 | L1 | visited=0 stack depth=1 | Call preorder(1), the root. |
| 3 | L3 | visited=1 stack depth=1 | Visit 1: before either subtree. |
| 4 | L1 | visited=1 stack depth=2 | Call preorder(2), depth 1. |
| 5 | L3 | visited=2 stack depth=2 | Visit 2: before either subtree. |
| 6 | L1 | visited=2 stack depth=3 | Call preorder(4), depth 2. |
| 7 | L3 | visited=3 stack depth=3 | Visit 4: before either subtree. |
| 8 | L4 | visited=3 stack depth=3 | The left child of 4 is empty, so that call returns at once. |
| 9 | L5 | visited=3 stack depth=3 | The right child of 4 is empty, so that call returns at once. |
| 10 | L1 | visited=3 stack depth=3 | Call preorder(5), depth 2. |
| 11 | L3 | visited=4 stack depth=3 | Visit 5: before either subtree. |
| 12 | L4 | visited=4 stack depth=3 | The left child of 5 is empty, so that call returns at once. |
| 13 | L5 | visited=4 stack depth=3 | The right child of 5 is empty, so that call returns at once. |
| 14 | L1 | visited=4 stack depth=2 | Call preorder(3), depth 1. |
| 15 | L3 | visited=5 stack depth=2 | Visit 3: before either subtree. |
| 16 | L4 | visited=5 stack depth=2 | The left child of 3 is empty, so that call returns at once. |
| 17 | L1 | visited=5 stack depth=3 | Call preorder(6), depth 2. |
| 18 | L3 | visited=6 stack depth=3 | Visit 6: before either subtree. |
| 19 | L4 | visited=6 stack depth=3 | The left child of 6 is empty, so that call returns at once. |
| 20 | L5 | visited=6 stack depth=3 | The right child of 6 is empty, so that call returns at once. |
| 21 | L1 | visited=6 | Preorder: [1, 2, 4, 5, 3, 6]. |
Postorder
**Postorder** visits both subtrees and then the node. Children are always handled before their parent, which is what you need when a node's answer depends on its children's answers: heights, sizes, sums, deleting a tree, evaluating an expression tree.
The sequence for the sample tree is [4, 5, 2, 6, 3, 1]: the root comes last. Most of the structural computations in this chapter are postorder in disguise: the function returns a value for the subtree and the parent combines them.
1static void postorder(TreeNode n, List<Integer> out) {2if (n == null) return;3postorder(n.left, out);4postorder(n.right, out);5out.add(n.val); // visit last6}
Best
O(n)
Average
O(n)
Worst
O(n)
Space
O(h) call stack
Binary tree traversals: preorder, inorder, postorder and level order
Interactive · edit the inputbinary tree · 6 nodes
output
Preorder traversal of a tree with 6 nodes. The recursion's call stack remembers the path back to the root.
1static void preorder(TreeNode n, List<Integer> out) {2if (n == null) return; // empty subtree: nothing to visit3out.add(n.val); // visit the node first4preorder(n.left, out);5preorder(n.right, out);6}7static void inorder(TreeNode n, List<Integer> out) {8if (n == null) return;9inorder(n.left, out);10out.add(n.val); // visit between the two subtrees11inorder(n.right, out);12}13static void postorder(TreeNode n, List<Integer> out) {14if (n == null) return;15postorder(n.left, out);16postorder(n.right, out);17out.add(n.val); // visit after both subtrees18}19static List<Integer> levelOrder(TreeNode root) {20List<Integer> out = new ArrayList<>();21Deque<TreeNode> queue = new ArrayDeque<>();22if (root != null) queue.add(root);23while (!queue.isEmpty()) {24TreeNode n = queue.poll(); // oldest node first25out.add(n.val);26if (n.left != null) queue.add(n.left);27if (n.right != null) queue.add(n.right);28}29return out;30}
Live state
visited
0
Execution trace (dry run table)Show 21 stepsHide
| Step | Line | State | What happens |
|---|---|---|---|
| 1 | L1 | visited=0 | Preorder traversal of a tree with 6 nodes. The recursion's call stack remembers the path back to the root. |
| 2 | L1 | visited=0 stack depth=1 | Call preorder(1), the root. |
| 3 | L3 | visited=1 stack depth=1 | Visit 1: before either subtree. |
| 4 | L1 | visited=1 stack depth=2 | Call preorder(2), depth 1. |
| 5 | L3 | visited=2 stack depth=2 | Visit 2: before either subtree. |
| 6 | L1 | visited=2 stack depth=3 | Call preorder(4), depth 2. |
| 7 | L3 | visited=3 stack depth=3 | Visit 4: before either subtree. |
| 8 | L4 | visited=3 stack depth=3 | The left child of 4 is empty, so that call returns at once. |
| 9 | L5 | visited=3 stack depth=3 | The right child of 4 is empty, so that call returns at once. |
| 10 | L1 | visited=3 stack depth=3 | Call preorder(5), depth 2. |
| 11 | L3 | visited=4 stack depth=3 | Visit 5: before either subtree. |
| 12 | L4 | visited=4 stack depth=3 | The left child of 5 is empty, so that call returns at once. |
| 13 | L5 | visited=4 stack depth=3 | The right child of 5 is empty, so that call returns at once. |
| 14 | L1 | visited=4 stack depth=2 | Call preorder(3), depth 1. |
| 15 | L3 | visited=5 stack depth=2 | Visit 3: before either subtree. |
| 16 | L4 | visited=5 stack depth=2 | The left child of 3 is empty, so that call returns at once. |
| 17 | L1 | visited=5 stack depth=3 | Call preorder(6), depth 2. |
| 18 | L3 | visited=6 stack depth=3 | Visit 6: before either subtree. |
| 19 | L4 | visited=6 stack depth=3 | The left child of 6 is empty, so that call returns at once. |
| 20 | L5 | visited=6 stack depth=3 | The right child of 6 is empty, so that call returns at once. |
| 21 | L1 | visited=6 | Preorder: [1, 2, 4, 5, 3, 6]. |
Recursive DFS
The three orders are all **depth-first search**: follow one branch to the bottom before trying the next. The recursion makes the call stack remember the path from the root to the current node, which the animation draws as the list of active calls. They differ only in *where* the visit happens relative to the two recursive calls.
The stack depth is the tree's height, plus one frame for the null call. For a balanced tree that is about log n, but for a degenerate tree with n nodes it is n, and a deep enough chain overflows Java's thread stack. That is the reason to learn the iterative versions in the next lesson.
| Order | Visit happens | Typical use |
|---|---|---|
| Preorder | before the subtrees | copy a tree, serialise, prefix expressions |
| Inorder | between the subtrees | sorted keys of a BST |
| Postorder | after the subtrees | heights, sizes, deleting, postfix expressions |
Binary tree traversals: preorder, inorder, postorder and level order
Interactive · edit the inputbinary tree · 6 nodes
output
Preorder traversal of a tree with 6 nodes. The recursion's call stack remembers the path back to the root.
1static void preorder(TreeNode n, List<Integer> out) {2if (n == null) return; // empty subtree: nothing to visit3out.add(n.val); // visit the node first4preorder(n.left, out);5preorder(n.right, out);6}7static void inorder(TreeNode n, List<Integer> out) {8if (n == null) return;9inorder(n.left, out);10out.add(n.val); // visit between the two subtrees11inorder(n.right, out);12}13static void postorder(TreeNode n, List<Integer> out) {14if (n == null) return;15postorder(n.left, out);16postorder(n.right, out);17out.add(n.val); // visit after both subtrees18}19static List<Integer> levelOrder(TreeNode root) {20List<Integer> out = new ArrayList<>();21Deque<TreeNode> queue = new ArrayDeque<>();22if (root != null) queue.add(root);23while (!queue.isEmpty()) {24TreeNode n = queue.poll(); // oldest node first25out.add(n.val);26if (n.left != null) queue.add(n.left);27if (n.right != null) queue.add(n.right);28}29return out;30}
Live state
visited
0
Execution trace (dry run table)Show 21 stepsHide
| Step | Line | State | What happens |
|---|---|---|---|
| 1 | L1 | visited=0 | Preorder traversal of a tree with 6 nodes. The recursion's call stack remembers the path back to the root. |
| 2 | L1 | visited=0 stack depth=1 | Call preorder(1), the root. |
| 3 | L3 | visited=1 stack depth=1 | Visit 1: before either subtree. |
| 4 | L1 | visited=1 stack depth=2 | Call preorder(2), depth 1. |
| 5 | L3 | visited=2 stack depth=2 | Visit 2: before either subtree. |
| 6 | L1 | visited=2 stack depth=3 | Call preorder(4), depth 2. |
| 7 | L3 | visited=3 stack depth=3 | Visit 4: before either subtree. |
| 8 | L4 | visited=3 stack depth=3 | The left child of 4 is empty, so that call returns at once. |
| 9 | L5 | visited=3 stack depth=3 | The right child of 4 is empty, so that call returns at once. |
| 10 | L1 | visited=3 stack depth=3 | Call preorder(5), depth 2. |
| 11 | L3 | visited=4 stack depth=3 | Visit 5: before either subtree. |
| 12 | L4 | visited=4 stack depth=3 | The left child of 5 is empty, so that call returns at once. |
| 13 | L5 | visited=4 stack depth=3 | The right child of 5 is empty, so that call returns at once. |
| 14 | L1 | visited=4 stack depth=2 | Call preorder(3), depth 1. |
| 15 | L3 | visited=5 stack depth=2 | Visit 3: before either subtree. |
| 16 | L4 | visited=5 stack depth=2 | The left child of 3 is empty, so that call returns at once. |
| 17 | L1 | visited=5 stack depth=3 | Call preorder(6), depth 2. |
| 18 | L3 | visited=6 stack depth=3 | Visit 6: before either subtree. |
| 19 | L4 | visited=6 stack depth=3 | The left child of 6 is empty, so that call returns at once. |
| 20 | L5 | visited=6 stack depth=3 | The right child of 6 is empty, so that call returns at once. |
| 21 | L1 | visited=6 | Preorder: [1, 2, 4, 5, 3, 6]. |
Iterative stack traversals
An iterative traversal keeps the stack the recursion kept implicitly. **Preorder**: push the root; pop a node, visit it, push its right child and then its left, so that the left is popped first. **Inorder**: go left as far as possible pushing every node; pop one and visit it; then continue from its right child. **Postorder** is the awkward one: either run a modified preorder (node, right, left) and reverse the output, or track the last visited node to know when a node's right subtree is finished.
The animation “Iterative tree traversal” (from the stack chapter) shows the stack contents at each step for all three; the stack never holds more than the tree's height plus one node, so the space is O(h).
1static List<Integer> preorderIter(TreeNode root) {2List<Integer> out = new ArrayList<>();3Deque<TreeNode> stack = new ArrayDeque<>();4if (root != null) stack.push(root);5while (!stack.isEmpty()) {6TreeNode n = stack.pop();7out.add(n.val);8if (n.right != null) stack.push(n.right); // pushed first, so popped last9if (n.left != null) stack.push(n.left);10}11return out;12}1314static List<Integer> inorderIter(TreeNode root) {15List<Integer> out = new ArrayList<>();16Deque<TreeNode> stack = new ArrayDeque<>();17TreeNode cur = root;18while (cur != null || !stack.isEmpty()) {19while (cur != null) { stack.push(cur); cur = cur.left; } // walk down the left spine20cur = stack.pop();21out.add(cur.val);22cur = cur.right;23}24return out;25}2627static List<Integer> postorderIter(TreeNode root) {28LinkedList<Integer> out = new LinkedList<>();29Deque<TreeNode> stack = new ArrayDeque<>();30if (root != null) stack.push(root);31while (!stack.isEmpty()) {32TreeNode n = stack.pop();33out.addFirst(n.val); // node, right, left, built backwards34if (n.left != null) stack.push(n.left);35if (n.right != null) stack.push(n.right);36}37return out;38}
Best
O(n)
Average
O(n)
Worst
O(n)
Space
O(h)
Depth-first traversal with an explicit stack
Interactive · edit the inputHeap as a binary tree · 7 nodes
1, 2, 3, 4, 5, 6, 7
int[] arr · length 7
stack of node indexes (top is last)
visit order
Inorder visits the left subtree, the node, then the right subtree. The stack replaces the call stack that recursion would use.
1// nodes are array indexes: children of i are 2i + 1 and 2i + 22// preorder: node, left, right. Push right first so left is popped first.3Deque<Integer> st = new ArrayDeque<>(); st.push(0);4while (!st.isEmpty()) { int i = st.pop(); visit(i); if (2*i+2 < n) st.push(2*i+2); if (2*i+1 < n) st.push(2*i+1); }5// inorder: left, node, right. Walk left, remember the path on the stack.6int cur = 0; while (cur < n || !st.isEmpty()) {7while (cur < n) { st.push(cur); cur = 2*cur + 1; } // go as far left as possible8int i = st.pop(); visit(i); cur = 2*i + 2; // then the right subtree9}10// postorder: left, right, node. Visit a node only after its right child was visited.11int last = -1; cur = 0; while (cur < n || !st.isEmpty()) {12if (cur < n) { st.push(cur); cur = 2*cur + 1; }13else { int top = st.peek(), r = 2*top + 2;14if (r < n && last != r) cur = r; else { visit(top); last = st.pop(); } }15}
Live state
Execution trace (dry run table)Show 16 stepsHide
| Step | Line | State | What happens |
|---|---|---|---|
| 1 | L6 | Inorder visits the left subtree, the node, then the right subtree. The stack replaces the call stack that recursion would use. | |
| 2 | L7 | cur=1 | Push 1 and keep going left. |
| 3 | L7 | cur=2 | Push 2 and keep going left. |
| 4 | L7 | cur=4 | Push 4 and keep going left. |
| 5 | L8 | visit=4 | No left child left: pop 4 and visit it, then move to its right subtree. |
| 6 | L8 | visit=2 | No left child left: pop 2 and visit it, then move to its right subtree. |
| 7 | L7 | cur=5 | Push 5 and keep going left. |
| 8 | L8 | visit=5 | No left child left: pop 5 and visit it, then move to its right subtree. |
| 9 | L8 | visit=1 | No left child left: pop 1 and visit it, then move to its right subtree. |
| 10 | L7 | cur=3 | Push 3 and keep going left. |
| 11 | L7 | cur=6 | Push 6 and keep going left. |
| 12 | L8 | visit=6 | No left child left: pop 6 and visit it, then move to its right subtree. |
| 13 | L8 | visit=3 | No left child left: pop 3 and visit it, then move to its right subtree. |
| 14 | L7 | cur=7 | Push 7 and keep going left. |
| 15 | L8 | visit=7 | No left child left: pop 7 and visit it, then move to its right subtree. |
| 16 | L9 | return=[4, 2, 5, 1, 6, 3, 7] | Inorder: [4, 2, 5, 1, 6, 3, 7]. The stack never holds more than the tree height plus one: O(h) space. |
Level-order BFS
**Level order** visits nodes by depth: the root, then its children, then the grandchildren. It is **breadth-first search** and uses a **queue**: take the oldest node, visit it, add its children at the back. On the sample tree the result is [1, 2, 3, 4, 5, 6].
The queue holds at most one level plus part of the next, so the space is O(w) for width w, which for a balanced tree is about n / 2 at the bottom level. Depth-first uses O(h) and breadth-first O(w); which is smaller depends on the shape. The next lesson group builds all the 'by level' and 'view' problems on this loop.
1static List<Integer> levelOrder(TreeNode root) {2List<Integer> out = new ArrayList<>();3Deque<TreeNode> queue = new ArrayDeque<>();4if (root != null) queue.add(root);5while (!queue.isEmpty()) {6TreeNode n = queue.poll(); // oldest first7out.add(n.val);8if (n.left != null) queue.add(n.left);9if (n.right != null) queue.add(n.right);10}11return out;12}
Best
O(n)
Average
O(n)
Worst
O(n)
Space
O(w), w = widest level
Binary tree traversals: preorder, inorder, postorder and level order
Interactive · edit the inputbinary tree · 6 nodes
output
Preorder traversal of a tree with 6 nodes. The recursion's call stack remembers the path back to the root.
1static void preorder(TreeNode n, List<Integer> out) {2if (n == null) return; // empty subtree: nothing to visit3out.add(n.val); // visit the node first4preorder(n.left, out);5preorder(n.right, out);6}7static void inorder(TreeNode n, List<Integer> out) {8if (n == null) return;9inorder(n.left, out);10out.add(n.val); // visit between the two subtrees11inorder(n.right, out);12}13static void postorder(TreeNode n, List<Integer> out) {14if (n == null) return;15postorder(n.left, out);16postorder(n.right, out);17out.add(n.val); // visit after both subtrees18}19static List<Integer> levelOrder(TreeNode root) {20List<Integer> out = new ArrayList<>();21Deque<TreeNode> queue = new ArrayDeque<>();22if (root != null) queue.add(root);23while (!queue.isEmpty()) {24TreeNode n = queue.poll(); // oldest node first25out.add(n.val);26if (n.left != null) queue.add(n.left);27if (n.right != null) queue.add(n.right);28}29return out;30}
Live state
visited
0
Execution trace (dry run table)Show 21 stepsHide
| Step | Line | State | What happens |
|---|---|---|---|
| 1 | L1 | visited=0 | Preorder traversal of a tree with 6 nodes. The recursion's call stack remembers the path back to the root. |
| 2 | L1 | visited=0 stack depth=1 | Call preorder(1), the root. |
| 3 | L3 | visited=1 stack depth=1 | Visit 1: before either subtree. |
| 4 | L1 | visited=1 stack depth=2 | Call preorder(2), depth 1. |
| 5 | L3 | visited=2 stack depth=2 | Visit 2: before either subtree. |
| 6 | L1 | visited=2 stack depth=3 | Call preorder(4), depth 2. |
| 7 | L3 | visited=3 stack depth=3 | Visit 4: before either subtree. |
| 8 | L4 | visited=3 stack depth=3 | The left child of 4 is empty, so that call returns at once. |
| 9 | L5 | visited=3 stack depth=3 | The right child of 4 is empty, so that call returns at once. |
| 10 | L1 | visited=3 stack depth=3 | Call preorder(5), depth 2. |
| 11 | L3 | visited=4 stack depth=3 | Visit 5: before either subtree. |
| 12 | L4 | visited=4 stack depth=3 | The left child of 5 is empty, so that call returns at once. |
| 13 | L5 | visited=4 stack depth=3 | The right child of 5 is empty, so that call returns at once. |
| 14 | L1 | visited=4 stack depth=2 | Call preorder(3), depth 1. |
| 15 | L3 | visited=5 stack depth=2 | Visit 3: before either subtree. |
| 16 | L4 | visited=5 stack depth=2 | The left child of 3 is empty, so that call returns at once. |
| 17 | L1 | visited=5 stack depth=3 | Call preorder(6), depth 2. |
| 18 | L3 | visited=6 stack depth=3 | Visit 6: before either subtree. |
| 19 | L4 | visited=6 stack depth=3 | The left child of 6 is empty, so that call returns at once. |
| 20 | L5 | visited=6 stack depth=3 | The right child of 6 is empty, so that call returns at once. |
| 21 | L1 | visited=6 | Preorder: [1, 2, 4, 5, 3, 6]. |
Practice ladder
Now try it yourself
Easy
- Binary Tree Preorder Traversal
- Binary Tree Inorder Traversal
- Binary Tree Postorder Traversal
Medium
- Binary Tree Level Order Traversal
- Kth Smallest Element in a BST
Advanced
- Binary Tree Postorder Traversal (one stack)
- Morris Inorder Traversal
Key takeaways
- Preorder, inorder and postorder differ only in where the visit sits relative to the two recursive calls.
- Inorder on a BST is sorted; postorder handles children before parents.
- Recursive DFS uses stack space equal to the tree height, which is n for a chain.
- Explicit stacks rewrite DFS iteratively; a queue gives level order.