Menu

Earn Premium with Referrals

Invite your friends and earn Premium rewards through our referral program.

See how it works and start inviting friends.

BFS & Level Order
DSA

BFS & Level Order

Understand how queues enable level-by-level traversal and processing of trees.

BFS (Level Order) traverses a tree level by level, processing all nodes at the same depth before moving deeper.

Its core advantage:

BFS guarantees the shortest path in unweighted trees and enables level-aware problems.

Focus on recognizing:

“Level by level” + “Queue” + “Breadth” = BFS / Level Order


Pattern Table

PatternTypical QuestionsTrigger
Level OrderReturn levels as listsQueue + size batching
Right/Left ViewSee first node at each levelTrack first/last in level
ZigzagAlternating left-rightToggle direction per level

Mental Trigger

Queue → Process level size → Add children → Repeat.


1. Generic Java BFS Template (Base)

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

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

    while (!queue.isEmpty()) {
        int size = queue.size();
        List<Integer> level = new ArrayList<>();

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

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

        result.add(level);
    }

    return result;
}
from collections import deque

def level_order(root):
    result = []
    if root is None:
        return result

    queue = deque([root])

    while queue:
        size = len(queue)
        level = []

        for _ in range(size):
            node = queue.popleft()
            level.append(node.val)

            if node.left:
                queue.append(node.left)
            if node.right:
                queue.append(node.right)

        result.append(level)

    return result
vector<vector<int>> levelOrder(TreeNode* root) {
    vector<vector<int>> result;
    if (root == nullptr) return result;

    queue<TreeNode*> q;
    q.push(root);

    while (!q.empty()) {
        int size = q.size();
        vector<int> level;

        for (int i = 0; i < size; i++) {
            TreeNode* node = q.front();
            q.pop();
            level.push_back(node->val);

            if (node->left != nullptr) q.push(node->left);
            if (node->right != nullptr) q.push(node->right);
        }

        result.push_back(level);
    }

    return result;
}
function levelOrder(root) {
  const result = [];
  if (root === null) return result;

  const queue = [root];

  while (queue.length > 0) {
    const size = queue.length;
    const level = [];

    for (let i = 0; i < size; i++) {
      const node = queue.shift();
      level.push(node.val);

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

    result.push(level);
  }

  return result;
}

Everything else in Level Order is just a modification of this template.


Pattern 1: Right Side View

Last node dequeued per level = what you see from the right. Press to animate.

Right Side View

Return the last node visible on each level when the tree is viewed from the right.

BFS level by level using a queue; the final node dequeued in each level is exactly the rightmost node. No depth-tracking DFS needed.

TREE VISUALIZER
Steps
12354
Press ▶ to animate, or step through manually.
Variables
keys: ← → space F
Pseudocode

                        1
                        queue = [root]
                      
                        2
                        while queue:
                      
                        3
                          size = len(queue)          // level marker
                      
                        4
                          for i in 0..size-1:
                      
                        5
                            n = dequeue; if i == size-1 → visible
                      
                        6
                            enqueue children
                      

Java Code

public List<Integer> rightSideView(TreeNode root) {
    List<Integer> result = new ArrayList<>();
    if (root == null) return result;

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

    while (!queue.isEmpty()) {
        int size = queue.size();

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

            if (i == size - 1)
                result.add(node.val);

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

    return result;
}
def right_side_view(root):
    result = []
    if root is None:
        return result

    queue = deque([root])

    while queue:
        size = len(queue)

        for i in range(size):
            node = queue.popleft()

            if i == size - 1:
                result.append(node.val)

            if node.left:
                queue.append(node.left)
            if node.right:
                queue.append(node.right)

    return result
vector<int> rightSideView(TreeNode* root) {
    vector<int> result;
    if (root == nullptr) return result;

    queue<TreeNode*> q;
    q.push(root);

    while (!q.empty()) {
        int size = q.size();

        for (int i = 0; i < size; i++) {
            TreeNode* node = q.front();
            q.pop();

            if (i == size - 1)
                result.push_back(node->val);

            if (node->left != nullptr) q.push(node->left);
            if (node->right != nullptr) q.push(node->right);
        }
    }

    return result;
}
function rightSideView(root) {
  const result = [];
  if (root === null) return result;

  const queue = [root];

  while (queue.length > 0) {
    const size = queue.length;

    for (let i = 0; i < size; i++) {
      const node = queue.shift();

      if (i === size - 1)
        result.push(node.val);

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

  return result;
}

What Changed from the Base Template?

Track last node in each level

Base:

level.add(node.val); // add all nodes

Changed:

if (i == size - 1)
    result.add(node.val); // only add last node of level

because the right side view is the last (rightmost) node at each level.

Right Side View = Level Order + Add last node of each level.


Pattern 2: Zigzag Level Order

Same level BFS with a direction flag that flips each row. Press to animate.

Zigzag Level Order

Return tree values level by level, alternating left-to-right and right-to-left each row.

Standard BFS collects each level, then reverse the level when the direction flag is false and toggle it. Same skeleton as right-side view — only the per-level bookkeeping differs.

TREE VISUALIZER
Steps
3920157
Press ▶ to animate, or step through manually.
Variables
keys: ← → space F
Pseudocode

                        1
                        BFS by levels
                      
                        2
                        leftToRight = true
                      
                        3
                        collect level values
                      
                        4
                        if !leftToRight: reverse(level)
                      
                        5
                        toggle direction
                      

Java Code

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

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

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

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

            if (leftToRight)
                level.addLast(node.val);
            else
                level.addFirst(node.val);

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

        result.add(level);
        leftToRight = !leftToRight;
    }

    return result;
}
def zigzag_level_order(root):
    result = []
    if root is None:
        return result

    queue = deque([root])
    left_to_right = True

    while queue:
        size = len(queue)
        level = deque()

        for _ in range(size):
            node = queue.popleft()

            if left_to_right:
                level.append(node.val)
            else:
                level.appendleft(node.val)

            if node.left:
                queue.append(node.left)
            if node.right:
                queue.append(node.right)

        result.append(list(level))
        left_to_right = not left_to_right

    return result
vector<vector<int>> zigzagLevelOrder(TreeNode* root) {
    vector<vector<int>> result;
    if (root == nullptr) return result;

    queue<TreeNode*> q;
    q.push(root);
    bool leftToRight = true;

    while (!q.empty()) {
        int size = q.size();
        deque<int> level;

        for (int i = 0; i < size; i++) {
            TreeNode* node = q.front();
            q.pop();

            if (leftToRight)
                level.push_back(node->val);
            else
                level.push_front(node->val);

            if (node->left != nullptr) q.push(node->left);
            if (node->right != nullptr) q.push(node->right);
        }

        result.push_back(vector<int>(level.begin(), level.end()));
        leftToRight = !leftToRight;
    }

    return result;
}
function zigzagLevelOrder(root) {
  const result = [];
  if (root === null) return result;

  const queue = [root];
  let leftToRight = true;

  while (queue.length > 0) {
    const size = queue.length;
    const level = [];

    for (let i = 0; i < size; i++) {
      const node = queue.shift();

      if (leftToRight)
        level.push(node.val);
      else
        level.unshift(node.val);

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

    result.push(level);
    leftToRight = !leftToRight;
  }

  return result;
}

What Changed from the Base Template?

Toggle direction

Added:

boolean leftToRight = true;
// toggle each level
leftToRight = !leftToRight;

because zigzag alternates direction every level.


AddFirst or AddLast

Base:

level.add(node.val);

Changed:

if (leftToRight) level.addLast(node.val);
else level.addFirst(node.val);

to reverse the order of nodes in the level when going right-to-left.

Zigzag = Level Order + Toggle direction + AddFirst for reverse levels.


BFS Pattern Evolution

Base Level Order (queue + size batching)

Right Side View
    (+ last node of each level)

Zigzag
    (+ toggle direction + addFirst/addLast)

Common Mistakes

Not saving queue.size() before the inner loop.

The size changes as children are added — capture it once at the start.


Forgetting null check.

Always if (root == null) return before creating the queue.


Using poll on empty queue.

Check !queue.isEmpty() before polling.


Recognition Cheat Sheet

If you see…Think…
Level-by-level outputBFS with size batching
Right/left view of treeBFS + track last/first in level
Zigzag / spiral orderBFS + toggle direction
Minimum depthBFS + return when leaf found

My Private Notes

Notes are auto-saved locally to this device.