Python Arena
Step 4 of 6

Level order with a deque

The traversals of the last step go deep first: down the left side before anything on the right. Sometimes you want a tree level by level instead: the root, then its children, then their children, each level from left to right. That's level order, also called breadth-first search (BFS).

It needs a queue: first in, first out, like a line at a ticket counter. Put the root in the queue. Then, again and again, take the node at the front, visit it, and put its children at the back. A node's children wait behind every node that is already in line, so the whole level above them goes first.

collections.deque

A list makes a poor queue. queue.pop(0) removes the first item, and every other item moves one place to close the gap: O(n). The collections.deque (said "deck", short for double-ended queue) adds and removes at both of its ends in O(1):

In the Python interpreter
>>> from collections import deque
>>> queue = deque([10, 20])
>>> queue.append(30)
>>> queue.popleft()
10
>>> queue
deque([20, 30])
>>> len(queue)
2

Level by level

Here is level order, and a version that keeps the levels apart. Many questions need to know where one level ends: the widest level, the average of each level, the last node of each level. The trick: at the start of each round of the while loop, the queue holds exactly one whole level. So take len(queue) nodes in a for loop. Those are the level, and the children they add make up the next one:

from collections import deque


class Node:
    def __init__(self, value, left=None, right=None):
        self.value = value
        self.left = left
        self.right = right


def level_order(root):
    order = []
    queue = deque()
    if root is not None:
        queue.append(root)
    while queue:
        node = queue.popleft()
        order.append(node.value)
        if node.left is not None:
            queue.append(node.left)
        if node.right is not None:
            queue.append(node.right)
    return order


def levels(root):
    result = []
    queue = deque()
    if root is not None:
        queue.append(root)
    while queue:
        level = []
        for _ in range(len(queue)):
            node = queue.popleft()
            level.append(node.value)
            if node.left is not None:
                queue.append(node.left)
            if node.right is not None:
                queue.append(node.right)
        result.append(level)
    return result


#        8
#       / \
#      3   12
#     / \    \
#    1   6    15
root = Node(8, Node(3, Node(1), Node(6)), Node(12, None, Node(15)))
print(level_order(root))
print(levels(root))
Output
[8, 3, 12, 1, 6, 15]
[[8], [3, 12], [1, 6, 15]]

range(len(queue)) is worked out once, when the for loop starts, so the children appended during the round wait for the next round. The last value of each level is what you'd see looking at the tree from its right side: 8, 12 and 15 here.

Only real children go into the queue. Appending a None child would put it in line too, and node.value on it would stop the program with an AttributeError:

from collections import deque


class Node:
    def __init__(self, value, left=None, right=None):
        self.value = value
        self.left = left
        self.right = right


queue = deque([Node(8, Node(3))])
while queue:
    node = queue.popleft()
    print(node.value)
    queue.append(node.left)
    queue.append(node.right)
Output
8
3
Python stops with
Traceback (most recent call last):
  File "main.py", line 14, in <module>
    print(node.value)
          ^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'value'

What it costs

Each node goes into the queue once and comes out once, O(1) each with a deque: O(n) time. The memory is the queue, which never holds more than about two levels: O(w), for the widest level w. In a full tree the last level holds half of the nodes, so that can be O(n), while a depth-first traversal needs O(h). With a list and pop(0) you get the same answers, but each pop costs O(n), so a wide tree takes O(n²). And level order uses no recursion at all: a tree 100,000 levels deep is no problem.

Your task

Challenge 1 of 3

This program takes each node from the queue, puts its children at the back, and then prints a line with the node, a colon and the nodes waiting in the queue, from front to back: A: B C would mean that it took A, and B and C are waiting. What does it print? Type each line it prints.

Challenge 2

Write widest(root) that returns the number of nodes on the widest level of a tree, the level with the most nodes. An empty tree has no levels, so it gives 0. The tests include a tree 3,000 levels deep, so go level by level with a queue rather than with recursion.

For example, this program:

root = Node(8, Node(3, Node(1), Node(6)), Node(12, None, Node(15)))
print(widest(root))
print(widest(Node(5, Node(4, Node(3)))))

prints:

3
1

Challenge 3

Looking at a tree from its right side, you see one node on each level: the last one, the rightmost. Write right_view(root) that returns the values you'd see, from the top level down, as a list. A node on the left can be seen when nothing on its level is to its right. The tests include a tree 3,000 levels deep, so go level by level with a queue rather than with recursion.

For example, this program:

#        1
#       / \
#      2   3
#       \
#        5
root = Node(1, Node(2, None, Node(5)), Node(3))
print(right_view(root))

prints:

[1, 3, 5]