Skip to content
DSA trees 7 min read

Level-Order Traversal (BFS): Visiting a Tree Level by Level

Level-order traversal visits a tree breadth-first — all nodes at depth 0, then all nodes at depth 1, and so on, left to right. Where DFS traversals use a stack (or recursion), level-order uses a queue: you process a node and enqueue its children, so nodes come out in the exact order they should be visited. It runs in O(n) time.

We reuse the standard TreeNode.

The idea: a queue does the work

A queue is first-in, first-out. Start by enqueueing the root. Repeatedly dequeue a node, process it, and enqueue its non-null children. Because children are always added behind the current level, every node on a level is processed before any node on the next.

        (1)
       /   \
     (2)    (3)
     / \      \
   (4) (5)    (6)

Level-order: 1 2 3 4 5 6

Flat level-order

This emits every value in breadth-first order as a single list:

std::vector<int> levelOrder(TreeNode* root) {
    std::vector<int> out;
    if (root == nullptr) return out;
    std::queue<TreeNode*> q;
    q.push(root);
    while (!q.empty()) {
        TreeNode* node = q.front(); q.pop();
        out.push_back(node->val);
        if (node->left)  q.push(node->left);
        if (node->right) q.push(node->right);
    }
    return out;
}

For beginners: In JavaScript, using array.shift() to dequeue is O(n) per call. The example above uses a moving head index so each dequeue stays O(1).

Grouping by level

Often you want a list per level (e.g. for a zigzag print or a right-side view). The trick: snapshot the queue’s size at the start of each loop — that count is exactly how many nodes are on the current level.

std::vector<std::vector<int>> levelsOf(TreeNode* root) {
    std::vector<std::vector<int>> levels;
    if (root == nullptr) return levels;
    std::queue<TreeNode*> q;
    q.push(root);
    while (!q.empty()) {
        int count = q.size();
        std::vector<int> level;
        for (int i = 0; i < count; i++) {
            TreeNode* node = q.front(); q.pop();
            level.push_back(node->val);
            if (node->left)  q.push(node->left);
            if (node->right) q.push(node->right);
        }
        levels.push_back(level);
    }
    return levels;
}

Complexity

  • Time: O(n) — each node is enqueued and dequeued once.
  • Space: O(w) where w is the maximum width of the tree (the largest level). For a balanced tree this is up to about n/2, i.e. O(n) in the worst case.

Going deeper: Level-order is just breadth-first search on a tree. The same queue technique finds shortest paths in unweighted graphs.

Next steps

You can now walk a tree both deep and wide. Apply it to ordered data with binary search trees, or practice on the tree exercises.

Last updated June 25, 2026
Was this helpful?