Hello and welcome to our next lesson!
In our previous lessons, we dove deep into tree traversal using Depth-First Search (DFS), exploring preorder, inorder, and postorder traversals. You learned how to implement these both recursively and iteratively using a stack, always prioritizing going "deeper" into the tree before exploring siblings.
Today, we'll switch gears to a fundamentally different strategy that is just as important in competitive programming: Breadth-First Search (BFS). This lesson directly addresses the learning outcome: implementing level-order traversal using a queue. You'll discover how to explore a tree "layer by layer," a technique that opens the door to solving a new class of problems.
1. Breadth-First vs. Depth-First Traversal
The name "level-order traversal" perfectly describes the process. We visit all nodes on level 0 (the root), then all nodes on level 1, then all on level 2, and so on. This "wide before deep" approach is the essence of Breadth-First Search.

The key to achieving this lies in the data structure we use. While iterative DFS relied on a stack (Last-In, First-Out), BFS relies on a queue (First-In, First-Out).
Think of it like waiting in a line: the first person to get in line is the first person to be served. In our traversal, the first node we add to our "to-visit" list (the root) is the first one we process. This simple FIFO principle ensures we exhaust an entire level before moving to the next.
2. The BFS Algorithm with a Queue
The algorithm for level-order traversal is intuitive and elegant. It follows these steps:
- Create a queue and add the
rootnode to it. - Start a loop that continues as long as the queue is not empty.
- Inside the loop, dequeue a node (remove it from the front of the queue).
- "Visit" the dequeued node (e.g., add its value to a results list).
- Enqueue the node's left child, if it exists (add it to the back of the queue).
- Enqueue the node's right child, if it exists (add it to the back of the queue).
To see this process in action, watch the following conceptual overview.
Binary Tree Level Order Traversal - BFS - Leetcode 102
This video from NeetCode provides an excellent visual walkthrough of the BFS algorithm on a binary tree. It clearly shows how the queue's state changes as we traverse the tree level by level.
Watch from the beginning to 06:36. Pay close attention to how nodes are added to and removed from the queue, and how this corresponds to visiting the tree level by level.
The following diagram provides another static, step-by-step view of the process, reinforcing what you saw in the video.

3. Implementation: Grouping Nodes by Level
A common requirement in competitive programming problems, like LeetCode's "Binary Tree Level Order Traversal", is to return the result as a list of lists, where each inner list contains the nodes of a single level.
Our basic BFS algorithm gives us a single flat list. How can we modify it to group the nodes? The solution is a clever but simple extension.
Before processing a level, we can check the current size of the queue. That size tells us exactly how many nodes are on the current level. We can then run an inner loop that many times to process only the nodes of that level.
The following resource explains this crucial pattern in detail.
Breadth-First Search Fundamentals
This article from HelloInterview clearly explains the standard BFS algorithm and then shows the specific pattern for processing nodes level by level. This is the exact technique you need for today's outcome.
Read the section titled 'Processing Levels'. It details the logic of using an inner for-loop based on the queue's size to group nodes by level and provides a clean Python implementation.
Let's look at the complete Python code. We'll use collections.deque, which is a highly efficient implementation of a queue in Python, providing time complexity for append (enqueue) and popleft (dequeue) operations.
from collections import deque
# Assume this TreeNode class is defined from previous lessons
class TreeNode:
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = right
def level_order_traversal(root: TreeNode):
# Handle the edge case of an empty tree
if not root:
return []
result = []
queue = deque([root]) # Initialize the queue with the root node
while queue:
# 1. Get the number of nodes at the current level
level_size = len(queue)
current_level_nodes = []
# 2. Loop exactly that many times to process all nodes at this level
for _ in range(level_size):
# 3. Dequeue a node from the front
node = queue.popleft()
current_level_nodes.append(node.val)
# 4. Enqueue its children for the next level
if node.left:
queue.append(node.left)
if node.right:
queue.append(node.right)
# 5. Add the completed level to the result
result.append(current_level_nodes)
return result
To solidify your understanding, watch this part of the NeetCode video where the instructor implements this exact logic.
Binary Tree Level Order Traversal - BFS - Leetcode 102
This segment walks through the Python code for level-order traversal, explaining each line and how it contributes to grouping nodes by level.
Watch from 06:36 to 09:21 to see the code being written and explained.
Test your understanding!
Consider the following binary tree:
10
/ \
5 15
/ \ \
3 7 18
Trace the level_order_traversal function. What is the state of the result list and the queue after the while loop has completed its second iteration (i.e., after the level [5, 15] has been processed)?
Show answer
- Initial:
queue=deque([10]),result=[]. - First Iteration (level 0):
level_size= 1.- The loop runs once:
node= 10 is dequeued.current_level_nodes=[10]. Children 5 and 15 are enqueued. - After the inner loop:
queue=deque([5, 15]). result.append([10]). So,resultis[[10]].
- Second Iteration (level 1):
level_size= 2.- The loop runs twice:
node= 5 is dequeued.current_level_nodes=[5]. Children 3 and 7 are enqueued.queueis nowdeque([15, 3, 7]).node= 15 is dequeued.current_level_nodes=[5, 15]. Child 18 is enqueued.queueis nowdeque([3, 7, 18]).
- After the inner loop:
result.append([5, 15]).
Final State after the second iteration:
result:[[10], [5, 15]]queue:deque([3, 7, 18])(These are the nodes for the next level).
4. Complexity Analysis
Understanding the performance of this algorithm is crucial for competitive programming.
-
Time Complexity:
We visit every node in the tree exactly once. Each node is enqueued and dequeued once. Therefore, the time complexity is linear with respect to the number of nodes, . -
Space Complexity: or
The space complexity is determined by the maximum number of nodes stored in the queue at any given time. This corresponds to the maximum width () of the tree. In the worst-case scenario for a binary tree (a complete or "bushy" tree), the last level can contain up to nodes. Therefore, the worst-case space complexity is .
Conclusion
You have now mastered a second major tree traversal strategy: level-order traversal (or BFS). By understanding the roles of both stacks (for DFS) and queues (for BFS), you have significantly expanded your algorithmic toolkit.
Key Takeaways:
- Level-order traversal explores a tree layer by layer, which is a form of Breadth-First Search (BFS).
- The core data structure for BFS is a queue (First-In, First-Out), efficiently implemented in Python with
collections.deque. - To group nodes by level, a common pattern is to use a nested loop: an outer
whileloop to continue traversal and an innerforloop that iterateslen(queue)times to process a single level. - The algorithm has a time complexity of and a worst-case space complexity of .
Up Next:
With a solid grasp of both depth-first and breadth-first traversals, you are now equipped to tackle a wide variety of tree-based problems. In our next lesson, we will apply these traversal techniques to solve problems involving tree properties, such as calculating a tree's height or finding its diameter. You'll see how choosing the right traversal strategy can make solving these problems much more straightforward.