Attic
DSATrees

Traversals & BFS/DFS

Depth-first (Preorder, Inorder, Postorder) and breadth-first level-order traversals with recursive and iterative implementations

Tree traversal refers to the process of visiting (inspecting or updating) each node in a tree data structure exactly once. Traversals are categorized into Depth-First Search (DFS) and Breadth-First Search (BFS).


The Four Primary Traversals

Consider the following sample tree:

        1
       / \
      2   3
     / \
    4   5
  • Preorder (Root, Left, Right): 1, 2, 4, 5, 3
  • Inorder (Left, Root, Right): 4, 2, 5, 1, 3
  • Postorder (Left, Right, Root): 4, 5, 2, 3, 1
  • Level-Order (Breadth-first): 1, 2, 3, 4, 5

1. Depth-First Traversals (Recursive)

Recursive implementations leverage the implicit JVM call stack:

PreorderRecursive.java
// Root -> Left -> Right
public void preorder(TreeNode root, List<Integer> result) {
    if (root == null) return;

    result.add(root.val);         // 1. Visit root
    preorder(root.left, result);  // 2. Traverse left
    preorder(root.right, result); // 3. Traverse right
}

Key Applications: Tree copying, expression prefix evaluation, tree serialization.


2. Iterative Depth-First Traversals (Explicit Stack)

Iterative DFS replaces the JVM call stack with an explicit Deque<TreeNode> to prevent StackOverflowError on deep or degenerate trees:

IterativeInorder.java
public List<Integer> inorderTraversal(TreeNode root) {
    List<Integer> result = new ArrayList<>();
    Deque<TreeNode> stack = new ArrayDeque<>();
    TreeNode curr = root;

    while (curr != null || !stack.isEmpty()) {
        // 1. Traverse left as deep as possible
        while (curr != null) {
            stack.push(curr);
            curr = curr.left;
        }

        // 2. Pop node and visit
        curr = stack.pop();
        result.add(curr.val);

        // 3. Switch to right subtree
        curr = curr.right;
    }

    return result;
}

3. Breadth-First Search (Level-Order Traversal)

BFS traverses the tree level by level using a FIFO Queue<TreeNode>:

Level-by-Level Grouped Output

To group node values by their tree level (List<List<Integer>>), snapshot the queue size before draining each row:

LevelOrderTraversal.java
public List<List<Integer>> levelOrder(TreeNode root) {
    List<List<Integer>> result = new ArrayList<>();
    if (root == null) return result;

    Queue<TreeNode> queue = new ArrayDeque<>();
    queue.offer(root);

    while (!queue.isEmpty()) {
        int levelSize = queue.size(); // Snapshot current row width
        List<Integer> currentLevel = new ArrayList<>(levelSize);

        for (int i = 0; i < levelSize; i++) {
            TreeNode node = queue.poll();
            currentLevel.add(node.val);

            if (node.left != null) queue.offer(node.left);
            if (node.right != null) queue.offer(node.right);
        }

        result.add(currentLevel);
    }

    return result;
}

The queue.size() Snapshot Rule: Never call i < queue.size() directly inside the inner loop condition! As children are added with queue.offer(), queue.size() dynamically increases, causing the loop to mix levels together.

Zigzag / Spiral Level Order

Alternate row traversal direction (left-to-right on even levels, right-to-left on odd levels):

ZigzagTraversal.java
public List<List<Integer>> zigzagLevelOrder(TreeNode root) {
    List<List<Integer>> result = new ArrayList<>();
    if (root == null) return result;

    Queue<TreeNode> queue = new ArrayDeque<>();
    queue.offer(root);
    boolean leftToRight = true;

    while (!queue.isEmpty()) {
        int size = queue.size();
        LinkedList<Integer> currentLevel = new LinkedList<>();

        for (int i = 0; i < size; i++) {
            TreeNode node = queue.poll();

            // Insert at tail for left-to-right; at head for right-to-left
            if (leftToRight) {
                currentLevel.addLast(node.val);
            } else {
                currentLevel.addFirst(node.val);
            }

            if (node.left != null) queue.offer(node.left);
            if (node.right != null) queue.offer(node.right);
        }

        result.add(currentLevel);
        leftToRight = !leftToRight; // Flip direction per row
    }

    return result;
}

Traversal Complexity Comparison

TraversalTime ComplexityAuxiliary Space (Balanced Tree)Auxiliary Space (Worst-Case Skewed)Primary Use Case
PreorderO(n)O(log n) call stackO(n)Tree cloning, serialization, prefix math
InorderO(n)O(log n) call stackO(n)BST sorted extraction, checking BST validity
PostorderO(n)O(log n) call stackO(n)Bottom-up calculations (height, subtree sums)
Level-OrderO(n)O(w) ~ O(n) queueO(1) (single chain)Shortest path, tree width, visual printing

On this page