DSA Guide
Trees

N-ary Tree Preorder Traversal

Traverse a tree whose nodes have any number of children, recursively and iteratively

EasyDFS (Depth-First Search)
TreeDFSStack
Problem #589

Problem Statement

Given the root of an n-ary tree — a tree where each node can have any number of children — return the preorder traversal of its node values.

Preorder means: visit the node first, then traverse each child in order.

Input:        1
            / | \
           3  2  4
          / \
         5   6

Output: [1, 3, 5, 6, 2, 4]
Order:  root → subtree(3) fully → 2 → 4

Intuition

Preorder has a one-line recursive definition:

The key insight

Visit the node, then recursively traverse each child, left to right.

For a binary tree that is node, left, right. For an n-ary tree it is node, child₁, child₂, …, childₖ. The only change is that the fixed pair of children becomes a loop over a list.

The word "pre" refers to when the node itself is recorded: before its children. The three classic orders differ only in where that one line sits:

OrderNode recordedResult for the example
Preorderbefore the children1, 3, 5, 6, 2, 4
Postorderafter the children5, 6, 3, 2, 4, 1
Inorderbetween children (binary trees only)not defined for n-ary

Real-world analogy

Reading a table of contents. You read a chapter title, then everything inside that chapter (including its subsections) before moving to the next chapter. Title first, contents after — that is preorder.

Watch it run

Preorder over the n-ary tree (drawn here in binary positions for layout)
132564
Output[1]
Visit the root, 1, and record it immediately — that is what makes this preorder.
1 / 6
A subtree is fully explored before its sibling is touched — the signature of DFS.

Solution

Recursive

The definition translated directly into code.

from typing import Optional


class Node:
    def __init__(self, val: int = 0, children: Optional[list["Node"]] = None):
        self.val = val
        self.children = children if children is not None else []


def preorder(root: Optional[Node]) -> list[int]:
    """Node values in preorder: node first, then each child in order."""
    result: list[int] = []

    def visit(node: Optional[Node]) -> None:
        if node is None:
            return
        result.append(node.val)      # record BEFORE descending
        for child in node.children:
            visit(child)

    visit(root)
    return result

Iterative, with an explicit stack

Recursion uses the call stack; the iterative version manages that stack itself. This matters for very deep trees, where recursion would overflow.

def preorder_iterative(root: Optional[Node]) -> list[int]:
    if root is None:
        return []

    result: list[int] = []
    stack = [root]

    while stack:
        node = stack.pop()
        result.append(node.val)

        # Push children in REVERSE so the first child is popped first.
        for child in reversed(node.children):
            stack.append(child)

    return result

Why the children go on in reverse

A stack is last-in-first-out. Pushing children [3, 2, 4] in order makes 4 the top, so it would be visited first — the wrong order.

Pushing them reversed as 4, 2, 3 puts 3 on top, so it comes out first. Forgetting this reversal is the standard bug in iterative preorder.

Complexity Analysis

Time Complexity

O(n)

Space Complexity

O(h)

  • Time — every node is visited exactly once, and every child link is followed once.
  • SpaceO(h) where h is the height, for either the call stack or the explicit stack. A balanced tree gives O(log n); a degenerate chain gives O(n).

Recursive or iterative?

The recursive version is shorter and reads like the definition — prefer it unless the tree can be deep. Python's default recursion limit is 1000 frames, so a chain of 10,000 nodes raises RecursionError, and JavaScript engines throw RangeError at a similar depth. That is when the explicit stack earns its extra lines.

Edge Cases

On this page