3.4.3 · D5Trees
Question bank — Level-order traversal — BFS with queue
True or false — justify
A queue and a stack both hold "pending" nodes, so either produces level order.
False — a Stack (LIFO) serves the newest node first, diving deep down one path; only a queue's first-in-first-out order keeps the oldest (closest-to-root) node processed first, which is what level order needs.
On a tree, "distance from root" and "level/depth" are the same number.
True — a tree has exactly one path from root to any node, so the number of edges you walk (distance) equals the depth; that is why Breadth-First Search (BFS), which expands by increasing distance, gives level order here.
BFS always uses more memory than DFS.
False — BFS holds ~one level (width ), DFS holds ~one path (height ). On a tall skinny tree DFS is worse; on a wide bushy tree BFS is worse. Neither dominates.
If you replace deque.popleft() with list.pop(0), BFS still visits nodes in the correct order.
True for order, false for speed — you still get correct level order, but each
pop(0) shifts every element (), turning the whole traversal into .The queue can never hold more than one level's worth of nodes at once.
False — during a round the queue briefly holds the tail of the current level plus already-enqueued children of the next level, so it can hold up to roughly two partial levels; the snapshot trick is what keeps the grouping clean despite this.
Level-order traversal visits the root last because you process the front of the queue.
False — the root is enqueued first and therefore dequeued and visited first; "front of the queue" is the oldest item, and the root is the oldest.
Grouped BFS and flat BFS visit nodes in a different order.
False — they visit nodes in the same order; grouping only adds "fences" (via the size snapshot) to split that one stream into per-level sublists.
For a perfectly balanced binary tree, BFS space is .
False — space is , and the widest level (the bottom) of a complete tree holds nodes, so it is ; is the height, which governs DFS, not BFS.
Spot the error
while queue: node=dequeue(); visit(node); enqueue(node.left); enqueue(node.right) — what breaks?
It enqueues
None for missing children, so a later dequeue does None.left and crashes; guard with if node.left / if node.right before enqueuing.Grouped BFS reads for _ in range(len(queue)): but re-computes len(queue) inside the loop each iteration. What goes wrong?
The length grows as children are enqueued mid-loop, so the loop keeps running past the current level and bleeds nodes from the next floor into this group; snapshot
n = len(queue) once before the loop.Someone uses queue.append(node); node = queue.pop() (pop from the back) to "save memory". What order do they get?
pop() from the back is LIFO — they get a depth-first (pre-order-ish) walk down the rightmost-added path, not level order; see Depth-First Search (DFS).A program enqueues the root, then immediately checks if queue is empty: return before the loop, but the tree's root is None. What is the bug?
Enqueuing a
None root means the queue is not empty, so the loop runs and dereferences None; check if root is None: return [] before enqueuing anything.Code visits the node after enqueuing its children instead of before. Does output change?
For the flat node-visit order it makes no difference to which nodes appear when, since children of level are still processed only after all of level ; but mixing visit/enqueue order can matter if you also read queue state — keep visit → enqueue for clarity.
enqueue(node.right) is written before enqueue(node.left). What happens?
Within each level the output flips to right-to-left; the level grouping stays correct but the required left-to-right order is broken.
Why questions
Why does FIFO guarantee an entire level finishes before the next begins?
When all of level is enqueued, none of level has been enqueued yet; since we always dequeue the oldest, every level- node (and its child-enqueues) is handled before any level- node is reached.
Why is BFS space measured by width and not by the number of nodes ?
At any instant the queue holds only the frontier — roughly one level — so it grows with the widest level ; it only equals when the widest level itself is .
Why is BFS the natural way to find shortest paths in an unweighted graph?
Because it expands nodes strictly by increasing distance, the first time it reaches a node is via a fewest-edge path — see Shortest path in unweighted graphs.
Why does snapshotting the queue size give exactly the current level's count?
Right before a round begins, the queue contains precisely the nodes discovered on the previous round — i.e. the whole current level and nothing else — so its length is that level's node count.
Why does each node contribute work, making BFS overall?
Each node is enqueued exactly once and dequeued exactly once, and processing it (visit + push up to two children) is constant work, so total work scales linearly with node count.
Why does DFS use a stack while BFS uses a queue, if both just "hold pending nodes"?
The container's ordering is the algorithm: LIFO postpones siblings and dives deep (DFS), FIFO postpones depth and sweeps wide (BFS). Swapping the container swaps the traversal.
Edge cases
What does BFS output for an empty tree (root = None)?
An empty list
[] — the guard if root is None returns before enqueuing, so the loop never runs.On a single-node tree, what is the max queue size and space cost?
Max queue size is 1 (just the root), so space is ; there is one level with one node.
On a fully skewed tree (each node has one child, forming a path), what is BFS's space cost?
— the queue never holds more than one node at a time because each level has exactly one node; here width even though height .
On a complete binary tree, at what moment does the queue reach its largest size?
When the entire deepest (fullest) level is queued — about nodes — giving the worst-case space; this is the Tree height vs width trade-off at its extreme.
If every node's value is identical, does BFS behave differently?
No — traversal depends only on structure (parent/child links), not on values; the visit order and complexity are unchanged.
A node has a left child but no right child. How does the guarded loop handle it?
It enqueues the left child and skips the right (
if node.right is false), so no None enters the queue and the level width simply reflects the one real child.