Skip to main content

Welcome to a Grasp lesson

Create a free account to keep studying and create your own study path.

Lesson 41

Tree Traversal Techniques

Recommended resources

Hello! Welcome to the first lesson in our module on trees.

In our previous module, we explored linear data structures like stacks and queues. You saw how a stack's Last-In, First-Out (LIFO) nature makes it perfect for problems like evaluating mathematical expressions. We are now moving into the world of non-linear data structures, starting with one of the most fundamental: the binary tree.

Your knowledge of stacks will be immediately useful, as they are key to implementing one of the two main approaches to today's topic.

The learning outcome for this lesson is to implement preorder, inorder, and postorder traversals, both recursively and iteratively. These traversals are the foundational operations for almost any algorithm involving trees, making them a critical topic for your technical interviews and competitive programming goals.

What is Tree Traversal?

Traversing a tree means visiting every node in the tree exactly once in a systematic way. For a binary tree, at any given node, we have three basic operations we can perform:

  1. Process the current node (e.g., print its value). We'll call this 'Root'.
  2. Traverse its left subtree. We'll call this 'Left'.
  3. Traverse its right subtree. We'll call this 'Right'.

The order in which we perform these three operations gives us our main traversal types:

  • Preorder: Root -> Left -> Right
  • Inorder: Left -> Root -> Right
  • Postorder: Left -> Right -> Root

Let's dive into how to implement these, starting with the most intuitive approach: recursion.


1. Recursive Traversals

The recursive nature of a tree (a tree is a root node with two children, which are themselves roots of smaller trees) lends itself beautifully to recursive algorithms. The logic of a recursive traversal function directly mirrors the definition of the traversal itself.

To get a clear overview of these recursive traversals, let's watch a short video.

Recursive Preorder, Inorder, Postorder Traversal | Trees - 4

This video from Algorithms Made Easy clearly explains the concept behind the three main depth-first traversals and shows how the recursive calls work with a simple example.

Watch the video from 00:41 to 07:45. Pay close attention to how the order of operations (Data, Left, Right) defines each traversal and how the recursive code is structured for each one.

As you saw in the video, the code for all three recursive traversals is strikingly similar, with only a single line moved. Let's look at the Java code for each.

First, here is a standard TreeNode class that we will use in our examples:

class TreeNode {
    int val;
    TreeNode left;
    TreeNode right;

    TreeNode(int val) {
        this.val = val;
        this.left = null;
        this.right = null;
    }
}

Now, let's look at the implementation for each traversal, which you can find in the article "Mastering Binary Tree Traversal".

Mastering Binary Tree Traversal (with Java Code Examples)

This article provides clear, concise Java implementations for all traversal types. We'll use it as a reference for the code snippets.

You don't need to read the whole article now, but you can refer to the sections titled '1. In-order Traversal', '2. Pre-order Traversal', and '3. Post-order Traversal' to see the recursive code examples.

Preorder Traversal: Root -> Left -> Right

Use Case: Often used to create a copy of a tree, as you can create the root node before you recursively create its children.

public void preorderTraversal(TreeNode root) {
    if (root == null) return;
    System.out.print(root.val + " ");  // 1. Visit root
    preorderTraversal(root.left);      // 2. Visit left subtree
    preorderTraversal(root.right);     // 3. Visit right subtree
}

Inorder Traversal: Left -> Root -> Right

Use Case: Its most famous application is on a Binary Search Tree (BST), where an inorder traversal visits the nodes in ascending sorted order.

public void inorderTraversal(TreeNode root) {
    if (root == null) return;
    inorderTraversal(root.left);      // 1. Visit left subtree
    System.out.print(root.val + " ");  // 2. Visit root
    inorderTraversal(root.right);     // 3. Visit right subtree
}

Postorder Traversal: Left -> Right -> Root

Use Case: This is useful for deleting a tree from memory. You must delete the children before you can delete the parent node.

public void postorderTraversal(TreeNode root) {
    if (root == null) return;
    postorderTraversal(root.left);      // 1. Visit left subtree
    postorderTraversal(root.right);     // 2. Visit right subtree
    System.out.print(root.val + " ");  // 3. Visit root
}
Test your understanding!

Consider a Binary Search Tree. If you need to find the 3rd smallest element, which traversal would be most efficient to use and why?

Show answer

Inorder traversal would be the most efficient. An inorder traversal of a BST processes the nodes in sorted (ascending) order. You can perform an inorder traversal and simply stop after visiting the 3rd node. You don't need to traverse the entire tree.


2. Iterative Traversals

While recursion is elegant, interviewers will often ask for an iterative solution. This demonstrates a deeper understanding of the traversal mechanics and how to manage the program state explicitly using a stack. It also avoids potential StackOverflowError on very deep trees.

The key idea is to use a Stack to simulate the function call stack that recursion uses behind the scenes.

Iterative Preorder Traversal

This is the most straightforward iterative traversal. The logic closely follows the "visit, go left, go right" pattern.

LeetCode 144. Binary Tree Preorder Traversal ITERATIVELY - Interview Prep Ep 76

This video from Fisher Coder gives an excellent walkthrough of two common iterative approaches for preorder traversal. The second approach is particularly common in interviews.

Watch from 04:14 to 11:59. This section explains and codes a very standard stack-based iterative preorder traversal. Notice the crucial detail of pushing the right child onto the stack before the left child.

Here is the standard algorithm and code for iterative preorder:

  1. Create an empty stack and push the root node to it.
  2. Loop as long as the stack is not empty.
  3. Pop a node from the stack and process it (e.g., add its value to a list).
  4. Push its right child to the stack (if it's not null).
  5. Push its left child to the stack (if it's not null).

We push the right child first so that the left child is on top of the stack, ensuring it gets processed first, thus maintaining the Root -> Left -> Right order.

Preorder Tree Traversal using Stack
This image provides a clear, step-by-step trace of the iterative preorder algorithm, showing the state of the stack and the resulting output at each step.
public List<Integer> preorderTraversalIterative(TreeNode root) {
    List<Integer> result = new ArrayList<>();
    if (root == null) return result;

    Stack<TreeNode> stack = new Stack<>();
    stack.push(root);

    while (!stack.isEmpty()) {
        TreeNode node = stack.pop();
        result.add(node.val); // Visit root

        // Push right child first, so left child is processed first
        if (node.right != null) {
            stack.push(node.right);
        }
        if (node.left != null) {
            stack.push(node.left);
        }
    }
    return result;
}

Iterative Inorder Traversal

The iterative inorder algorithm is slightly different and less direct than preorder, but it beautifully simulates the recursive descent to the leftmost node.

Iterative Inorder Traversal in Binary Tree Using Stack
This diagram breaks down the iterative inorder traversal process, showing how the stack is used to keep track of parent nodes as we traverse down the left side of the tree.

Here is the algorithm:

  1. Initialize an empty stack and a current node pointer set to root.
  2. Loop as long as current is not null OR the stack is not empty.
  3. Go Left: While current is not null, push it onto the stack and set current = current.left.
  4. Visit Root: When current becomes null, it means we've gone as far left as possible. Pop a node from the stack, process it.
  5. Go Right: Set current to the popped node's right child. The loop will then repeat, finding the leftmost node of this new subtree.
public List<Integer> inorderTraversalIterative(TreeNode root) {
    List<Integer> result = new ArrayList<>();
    Stack<TreeNode> stack = new Stack<>();
    TreeNode current = root;

    while (current != null || !stack.isEmpty()) {
        // 1. Go as far left as possible
        while (current != null) {
            stack.push(current);
            current = current.left;
        }

        // 2. current is null, so pop from stack
        current = stack.pop();
        result.add(current.val); // 3. Visit the node

        // 4. Move to the right subtree
        current = current.right;
    }
    return result;
}

Iterative Postorder Traversal

Iterative postorder is the trickiest of the three. A clever and easy-to-remember approach uses two stacks.

The idea is to perform a modified preorder traversal (Root -> Right -> Left) and use a second stack to reverse the order of visited nodes.

  1. Push the root node onto stack1.
  2. Loop while stack1 is not empty.
  3. Pop a node from stack1 and push it onto stack2.
  4. Push the popped node's left child to stack1 (if not null).
  5. Push the popped node's right child to stack1 (if not null).
  6. After the loop, the nodes in stack2 are in postorder. Pop them all and add to your result list.

Effectively, stack1 produces the order Root -> Right -> Left. When this is pushed onto stack2 and then popped, the resulting order is the reverse: Left -> Right -> Root, which is exactly postorder.

You can find the code for this in the "Mastering Binary Tree Traversal" article under the section "Code Snippet: Post-order Traversal (Iterative)".


Conclusion

You have now learned the three fundamental depth-first traversals for binary trees, covering both the elegant recursive solutions and the more explicit, stack-based iterative solutions that are common in interviews.

Key Takeaways:

  • Recursive vs. Iterative: Recursion is concise and intuitive. Iteration gives you more control, avoids recursion depth limits, and demonstrates mastery of stacks.
  • Traversal Orders & Use Cases:
    • Preorder (Root-L-R): Useful for copying a tree.
    • Inorder (L-Root-R): Produces a sorted sequence from a BST.
    • Postorder (L-R-Root): Essential for safely deleting a tree.
  • Complexity: All three traversals visit each node once, so the time complexity is O(N). The space complexity is O(H), where H is the height of the tree, for both the recursion call stack and the explicit stack in iterative methods. In the worst case (a skewed tree), H can be N.

A Glimpse into Advanced Traversals: For a great competitive programming challenge, you can try to perform all three traversals in a single pass using one stack. This involves storing a state with each node on the stack. The article "Preorder Inorder Postorder Traversals in One Traversal" on the takeuforward site (ID: [LINK](https://takeuforward.org/data-structure/preorder-inorder-postorder-traversals-in-one-traversal)) is an excellent resource if you want to explore this advanced technique.

Preview of the next lesson:
We've focused on "depth-first" traversals today. In our next lesson, we will explore a different strategy: "breadth-first" traversal, also known as level-order traversal. Instead of going deep, we will visit the tree level by level, for which we will use a queue instead of a stack.