Level-Order Traversal
Level-order traversal reads a binary tree the way you read a page: the root first, then its children left to right, then their children, row by row down to the last leaf. Under the costume it is plain breadth-first search - the same queue, pointed at a tree. It powers the famous [[level0], [level1], ...] answer shape from LeetCode, plus zigzag prints and "right side view" problems. One small trick - freezing the queue length before each round - turns the flat stream of nodes into clean per-level groups.
Watch the rows peel off
Press play - or drag the timeline and step through it yourself.Read this tree the way you read a page: row by row, top to bottom, left to right. A queue makes that order automatic.
Complexity
Greeting a family reunion, generation by generation
You arrive at a family reunion and want to greet everyone in a fair order: grandma first, then her children, then the grandchildren. So you keep a to-greet list. It starts with only grandma's name. Each time you greet the person at the top of the list, you add that person's children to the bottom. Because children always join the back of the line, a grandchild can never be greeted before an aunt or uncle - the list serves whole generations in order. That to-greet list is the queue, and the reunion is level-order traversal.
How it works, step by step
Put the root into a queue. The queue always holds the nodes waiting to be read.
Before each round, read `queue.length` once and save it as `size`. Exactly that many nodes belong to the current level.
Dequeue `size` nodes one by one. Each dequeued node joins the current level's array.
As you dequeue a node, push its left child, then its right child, to the back of the queue. They belong to the next level, safely behind the frozen count.
After `size` nodes, the level is complete. Push its array into the result and start the next round.
When the queue is empty, every node was read exactly once - O(n) time. The queue held at most one level, up to about n/2 nodes on a bushy tree.
The code, in JavaScript
The simple version: one queue, one output list. Note the index pointer - `shift()` would work, but it is O(n) per call. `head++` gives a real O(n) total.
const node = (val, left = null, right = null) => ({ val, left, right });
// The tree from the animation. Level sizes: 1, 2, 3, 2.
const root = node(3,
node(9, null, node(12)),
node(20, node(15, node(10), node(18)), node(7))
);
function levelOrderFlat(root) {
if (!root) return [];
const queue = [root];
const order = [];
let head = 0; // index pointer instead of shift()
while (head < queue.length) {
const cur = queue[head++]; // "dequeue" without moving memory
order.push(cur.val);
if (cur.left) queue.push(cur.left);
if (cur.right) queue.push(cur.right);
}
return order;
}
levelOrderFlat(root);
// → [3, 9, 20, 12, 15, 7, 10, 18]Dry run: reading the tree level by level
The same steps the visualizer plays, written as a table. Generated by running the real algorithm - not written by hand.
| Step | Level | What happened |
|---|---|---|
| 1 | 1 | Take 3 out of the queue and output it. Output: [3]. Queue: []. |
| 2 | 1 | Level 0 done: [3]. Queue now holds level 1: [9, 20]. |
| 3 | 2 | Take 9 out of the queue and output it. Output: [3, 9]. Queue: [20]. |
| 4 | 2 | Take 20 out of the queue and output it. Output: [3, 9, 20]. Queue: [12]. |
| 5 | 2 | Level 1 done: [9, 20]. Queue now holds level 2: [12, 15, 7]. |
| 6 | 3 | Take 12 out and output it. It is a leaf - nothing to add. Output: [3, 9, 20, 12]. Queue: [15, 7]. |
| 7 | 3 | Take 15 out of the queue and output it. Output: [3, 9, 20, 12, 15]. Queue: [7]. |
| 8 | 3 | Take 7 out and output it. It is a leaf - nothing to add. Output: [3, 9, 20, 12, 15, 7]. Queue: [10, 18]. |
| 9 | 3 | Level 2 done: [12, 15, 7]. Queue now holds level 3: [10, 18]. |
| 10 | 4 | Take 10 out and output it. It is a leaf - nothing to add. Output: [3, 9, 20, 12, 15, 7, 10]. Queue: [18]. |
| 11 | 4 | Take 18 out and output it. It is a leaf - nothing to add. Output: [3, 9, 20, 12, 15, 7, 10, 18]. Queue: []. |
| 12 | 4 | Level 3 done: [10, 18]. The queue is empty - every node has been read. |
Good choice when…
- The answer is per level: row averages, zigzag order, right side view, largest value in each row. All of them are this loop with one line changed.
- You need the minimum depth or the nearest matching node: the first level that satisfies the condition wins, and you can stop early.
- You are printing or serializing a tree top to bottom. Binary heaps are literally stored this way - an array in level order.
- The tree is very deep: the queue version cannot blow the call stack, unlike recursive DFS traversals.
Bad choice when…
- You want a BST's values in sorted order. That is in-order traversal's free gift - level order returns nothing sorted.
- Memory is tight and the tree is wide: the queue holds a whole level, up to about n/2 nodes at once. DFS holds only the height.
- The problem is naturally recursive - subtree sums, tree height, path sums. Those read much cleaner as DFS.
Common mistakes
- Read `const size = queue.length` before the inner loop. Checking `queue.length` live inside the loop counts the children you just pushed, and levels silently merge into one giant row. This is the number one bug in this problem.
- `array.shift()` is O(n) - it moves every remaining element one slot left. Called n times, it turns the traversal into O(n²). Use an index pointer (`queue[head++]`) on big trees.
- No BST needed. Level order never compares values, so it works on any binary tree. Do not confuse it with in-order, whose sorted-output trick only works on a BST.
- Level order alone cannot serialize a tree: [3, 9, 20] does not say which child is left and which is right, or where a child is missing. To rebuild the shape you must also record the `null` children - that is exactly LeetCode's `[3,9,20,null,null,15,7]` format.
Level-Order Traversal vs. its closest relatives
| Algorithm | Best | Average | Worst | Space | Stable |
|---|---|---|---|---|---|
| Level-Order Traversalthis page | O(n) | O(n) | O(n) | O(n) | - |
| Breadth-First Search | O(V + E) | O(V + E) | O(V + E) | O(V) | - |
| Tree Traversals | O(n) | O(n) | O(n) | O(h) | - |
| Binary Search Tree | O(log n) | O(log n) | O(n) | O(n) | - |