AlgoMaster Logo

Binary Tree Preorder Traversal

Last Updated: March 29, 2026

easy
4 min read

Understanding the Problem

We need to traverse a binary tree in preorder and return the node values as a list. Preorder traversal follows a specific visitation order: process the current node first, then recursively traverse the left subtree, then recursively traverse the right subtree. The name "preorder" comes from the fact that the node is processed before its children.

This is one of the three fundamental depth-first tree traversal patterns (preorder, inorder, postorder). While the recursive solution is straightforward, the real learning value here is understanding how to convert recursion into an iterative approach using an explicit stack, and then going further with Morris traversal to eliminate even the stack.

The key observation is that recursion uses the call stack implicitly. If we want to avoid recursion, we need to manage that stack ourselves. And if we want O(1) space, we need a clever trick with temporary thread links.

Key Constraints:

  • Number of nodes in range [0, 100] → With at most 100 nodes, any approach works. The focus here is on understanding traversal techniques, not optimizing for large inputs.
  • -100 <= Node.val <= 100 → Node values can be negative. This doesn't affect traversal logic.
  • The tree can be empty (0 nodes), so we need to handle the null root case.

Approach 1: Recursive DFS

Intuition

The recursive approach is the most natural way to think about preorder traversal. The definition itself is recursive: visit the current node, then preorder-traverse the left subtree, then preorder-traverse the right subtree. Translating that directly into code gives us a clean three-line recursive function.

This is usually where you'd start in an interview. It shows you understand the traversal order, and it's hard to get wrong. The recursion handles all the bookkeeping of which nodes to visit next by using the call stack.

Algorithm

  1. If the root is null, return an empty list.
  2. Create an empty result list.
  3. Define a recursive helper function preorder(node):
    • If node is null, return.
    • Add node.val to the result list.
    • Recurse on node.left.
    • Recurse on node.right.
  4. Call preorder(root) and return the result.

Example Walkthrough

1Start: call preorder(1)
1current23
1/4
1Result is empty
1/4

Code

The recursive approach uses the call stack implicitly. For deeply skewed trees, this can risk a stack overflow.

What if we managed the stack explicitly so we could control the memory?

Approach 2: Iterative with Stack

Intuition

The recursive solution uses the call stack to remember where to go next. We can make this explicit by using our own stack data structure. The insight is that preorder traversal processes the current node, then needs to visit the left subtree before the right subtree. Since a stack is LIFO (last in, first out), we push the right child first, then the left child. That way, the left child sits on top and gets processed first.

This is a classic interview technique: converting recursion to iteration using an explicit stack. It's worth knowing because interviewers often ask for the iterative version as a follow-up.

Algorithm

  1. If the root is null, return an empty list.
  2. Create an empty result list and a stack. Push the root onto the stack.
  3. While the stack is not empty:
    • Pop a node from the stack.
    • Add its value to the result list.
    • If the node has a right child, push it onto the stack.
    • If the node has a left child, push it onto the stack.
  4. Return the result.

Example Walkthrough

1Start: push root (1) onto stack
1pop2453
1/6
1Push root (1)
1
Top
1/6
1Result is empty
1/6

Code

Both the recursive and iterative approaches use O(h) extra space. Can we do better?

What if we could temporarily modify the tree structure to navigate back to ancestors without any extra space?

Approach 3: Morris Traversal (Optimal Space)

Intuition

Morris traversal is a clever technique that achieves O(1) extra space by temporarily modifying the tree. The core idea is: when we're about to explore a node's left subtree, we create a temporary link (a "thread") from the rightmost node in that left subtree back to the current node. This way, after finishing the left subtree, we can follow this thread back to the current node and continue with the right subtree, no stack needed.

For preorder specifically, we add the current node to the result as soon as we first encounter it (before going left). The thread just tells us how to get back.

Here's how to think about it: in a regular preorder traversal, after you finish the entire left subtree of a node, you need to somehow return to that node to visit its right subtree. Normally the stack handles this. Morris traversal instead says, "Before I go left, let me set up a breadcrumb trail so I can find my way back."

Algorithm

  1. Initialize current to the root and create an empty result list.
  2. While current is not null:
    • If current has no left child: add current.val to the result, move to current.right.
    • If current has a left child: find the inorder predecessor (rightmost node in left subtree).
      • If predecessor's right is null (first visit): create thread, add current.val to result, move left.
      • If predecessor's right is current (second visit): remove thread, move right.
  3. Return the result.

Example Walkthrough

1current=1, has left child. Find predecessor (5). Create thread 5->1. Visit 1
1current245predecessor3
1/7
1Visit 1
0
1
1/7

Code