Binary Trees · 7 of 35
Preorder Traversal of a tree both using recursion and Iteration
Visit every node of a tree as me first, then my left side, then my right side, with recursion and with your own pile of to-do cards.
- Simple way
- time O(n)
room O(h) - Clever way
- time O(n)
room O(h)
The problem, simply
You get a binary tree. Write down every value in this order: the node itself first, then everything in its left side, then everything in its right side. Do the same inside each side. This order is called preorder.
You must do it two ways: with a function that calls itself, and with a loop and your own stack.
A story to remember it
Picture it
The number under each node is when preorder reads it. A parent is always read before anyone in its family.
Examples
A normal tree
- In
[1, 2, 3, 4, 5, null, 6]- Out
[1, 2, 4, 5, 3, 6]
1 first, then its whole left family 2, 4, 5, then its right family 3, 6.
A stick leaning right
- In
[1, null, 2, null, 3]- Out
[1, 2, 3]
Every node has only a right child, so preorder walks straight down.
Only the root
- In
[7]- Out
[7]
One node, one value.
No tree
- In
[]- Out
[]
Return an empty list.
Way 1: the simple way
Write a helper that reads one node: write the node, then read the left side with itself, then the right side with itself.
- If the node is empty, return.
- Write the node's value.
- Read the left side.
- Read the right side.
Preorder writes a node the moment it arrives. While 4 is being written, 1 and 2 are already on the answer and their helpers are waiting.
- looking now
- done
- path
- just added
import java.util.*;
class Solution {
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> out = new ArrayList<>();
read(root, out);
return out;
}
private void read(TreeNode node, List<Integer> out) {
if (node == null) return;
out.add(node.val); // me first
read(node.left, out); // then left family
read(node.right, out); // then right family
}
}How long it takes: each node once, O(n). Extra room: the call stack, as tall as the tree, O(h).
Way 2: the clever way
Use the tour guide's pile of cards, a stack. A stack gives back the last thing you put in, so push the right child first and the left child second. Then the left child is on top and is handled first.
- Push the root.
- Pop the top node and write it.
- Push its right child, then its left child (skip empty ones).
- Repeat until the stack is empty.
Pop, write, push right then left
01 / 07
Put the root, 1, on the stack.
- looking now
- done
- answer
- just added
import java.util.*;
class Solution {
public List<Integer> preorderTraversal(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); // write me
if (node.right != null) stack.push(node.right); // right waits below
if (node.left != null) stack.push(node.left); // left on top, done next
}
return out;
}
}How long it takes: each node is pushed and popped once, O(n). Extra room: the stack. It holds at most one waiting right child per floor, plus the card on top, so O(h).
Way 3: no stack at all (Morris)
Like Morris inorder, borrow the empty right arrow of the last node in each left family as a ribbon back up. The only difference: write the node the first time you reach it (when you tie the ribbon), not the second time.
import java.util.*;
class Solution {
public List<Integer> preorderMorris(TreeNode root) {
List<Integer> out = new ArrayList<>();
TreeNode curr = root;
while (curr != null) {
if (curr.left == null) {
out.add(curr.val);
curr = curr.right;
} else {
TreeNode pre = curr.left;
while (pre.right != null && pre.right != curr) pre = pre.right;
if (pre.right == null) {
out.add(curr.val); // first visit: write now
pre.right = curr; // tie the ribbon
curr = curr.left;
} else {
pre.right = null; // second visit: untie and go right
curr = curr.right;
}
}
}
return out;
}
}It runs in O(n) time with O(1) extra room, and the tree is back to normal at the end.
Watch out for
- An empty root. Check it before pushing, or you will push
nulland crash onnode.val. - Using a queue instead of a stack gives level order, not preorder.
Stackin Java works but is old and slow.ArrayDequewithpushandpopis the usual choice.
What interviewers ask next
- Copy a tree, or save it to a string and load it back. Preorder with markers for empty children is the classic way, because the parent comes before its children.
- Flatten a tree into a linked list in preorder. Use the same stack loop and link each popped node to the next one.
- Get postorder from this code. Push left then right to get "me, right, left", then reverse the answer. That gives "left, right, me".
- Build a tree back from its preorder and inorder readings. The first preorder value is the root, and inorder tells you which values are on its left.
Remember this
Grown-up words: the pile of cards is a stack, last in is first out (LIFO), the helper that calls itself is recursion, and the ribbon version is Morris traversal using threads.