{"id":"dsa-trees-level-order","slug":"level-order","title":"Level order with a deque","text":"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).\n\nIt 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.\n\n### collections.deque\n\nA 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):\n\n```pycon\n>>> from collections import deque\n>>> queue = deque([10, 20])\n>>> queue.append(30)\n>>> queue.popleft()\n10\n>>> queue\ndeque([20, 30])\n>>> len(queue)\n2\n```\n\n### Level by level\n\nHere 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:\n\n```python\nfrom collections import deque\n\n\nclass Node:\n    def __init__(self, value, left=None, right=None):\n        self.value = value\n        self.left = left\n        self.right = right\n\n\ndef level_order(root):\n    order = []\n    queue = deque()\n    if root is not None:\n        queue.append(root)\n    while queue:\n        node = queue.popleft()\n        order.append(node.value)\n        if node.left is not None:\n            queue.append(node.left)\n        if node.right is not None:\n            queue.append(node.right)\n    return order\n\n\ndef levels(root):\n    result = []\n    queue = deque()\n    if root is not None:\n        queue.append(root)\n    while queue:\n        level = []\n        for _ in range(len(queue)):\n            node = queue.popleft()\n            level.append(node.value)\n            if node.left is not None:\n                queue.append(node.left)\n            if node.right is not None:\n                queue.append(node.right)\n        result.append(level)\n    return result\n\n\n#        8\n#       / \\\n#      3   12\n#     / \\    \\\n#    1   6    15\nroot = Node(8, Node(3, Node(1), Node(6)), Node(12, None, Node(15)))\nprint(level_order(root))\nprint(levels(root))\n```\n\n```output\n[8, 3, 12, 1, 6, 15]\n[[8], [3, 12], [1, 6, 15]]\n```\n\n`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.\n\nOnly 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`:\n\n```python\nfrom collections import deque\n\n\nclass Node:\n    def __init__(self, value, left=None, right=None):\n        self.value = value\n        self.left = left\n        self.right = right\n\n\nqueue = deque([Node(8, Node(3))])\nwhile queue:\n    node = queue.popleft()\n    print(node.value)\n    queue.append(node.left)\n    queue.append(node.right)\n```\n\n```output\n8\n3\n```\n\n```crash\nTraceback (most recent call last):\n  File \"main.py\", line 14, in <module>\n    print(node.value)\n          ^^^^^^^^^^\nAttributeError: 'NoneType' object has no attribute 'value'\n```\n\n### What it costs\n\nEach 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.\n","task":"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.\n","kind":"predict","seed":"from collections import deque\n\n\nclass Node:\n    def __init__(self, value, left=None, right=None):\n        self.value = value\n        self.left = left\n        self.right = right\n\n\n#        K\n#       / \\\n#      D   P\n#     / \\   \\\n#    B   H   T\n#       /\n#      F\ntree = Node(\"K\", Node(\"D\", Node(\"B\"), Node(\"H\", Node(\"F\"))), Node(\"P\", None, Node(\"T\")))\nqueue = deque([tree])\nwhile queue:\n    node = queue.popleft()\n    if node.left is not None:\n        queue.append(node.left)\n    if node.right is not None:\n        queue.append(node.right)\n    line = node.value + \":\"\n    for waiting in queue:\n        line += \" \" + waiting.value\n    print(line)\n","solution":"from collections import deque\n\n\nclass Node:\n    def __init__(self, value, left=None, right=None):\n        self.value = value\n        self.left = left\n        self.right = right\n\n\n#        K\n#       / \\\n#      D   P\n#     / \\   \\\n#    B   H   T\n#       /\n#      F\ntree = Node(\"K\", Node(\"D\", Node(\"B\"), Node(\"H\", Node(\"F\"))), Node(\"P\", None, Node(\"T\")))\nqueue = deque([tree])\nwhile queue:\n    node = queue.popleft()\n    if node.left is not None:\n        queue.append(node.left)\n    if node.right is not None:\n        queue.append(node.right)\n    line = node.value + \":\"\n    for waiting in queue:\n        line += \" \" + waiting.value\n    print(line)\n","hints":["Each round takes the node at the front, adds its children at the back, and only then prints. So the first line is `K: D P`, with K's children D and P waiting.","Next, D leaves and B and H join behind P. Children always join at the back of the line.","F is the child of H, so it joins when H leaves, behind T. The last line is `F:`, with nothing left in the queue."],"tests":[{"name":"Output","stdin":"","expect":"K: D P\nD: P B H\nP: B H T\nB: H T\nH: T F\nT: F\nF:","hidden":false}],"require":[],"forbid":[],"lines":["K: D P","D: P B H","P: B H T","B: H T","H: T F","T: F","F:"],"more":[{"task":"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.\n\nFor example, this program:\n\n```python\nroot = Node(8, Node(3, Node(1), Node(6)), Node(12, None, Node(15)))\nprint(widest(root))\nprint(widest(Node(5, Node(4, Node(3)))))\n```\n\nprints:\n\n```\n3\n1\n```\n","kind":"code","seed":"from collections import deque\n\n\nclass Node:\n    def __init__(self, value, left=None, right=None):\n        self.value = value\n        self.left = left\n        self.right = right\n\n\ndef widest(root):\n    pass\n\n\nif __name__ == \"__main__\":\n    root = Node(8, Node(3, Node(1), Node(6)), Node(12, None, Node(15)))\n    print(widest(root))\n    print(widest(Node(5, Node(4, Node(3)))))\n","solution":"from collections import deque\n\n\nclass Node:\n    def __init__(self, value, left=None, right=None):\n        self.value = value\n        self.left = left\n        self.right = right\n\n\ndef widest(root):\n    best = 0\n    queue = deque()\n    if root is not None:\n        queue.append(root)\n    while queue:\n        best = max(best, len(queue))\n        for _ in range(len(queue)):\n            node = queue.popleft()\n            if node.left is not None:\n                queue.append(node.left)\n            if node.right is not None:\n                queue.append(node.right)\n    return best\n\n\nif __name__ == \"__main__\":\n    root = Node(8, Node(3, Node(1), Node(6)), Node(12, None, Node(15)))\n    print(widest(root))\n    print(widest(Node(5, Node(4, Node(3)))))\n","hints":["Go level by level, as the lesson's `levels` does: at the start of each round of the `while` loop, the queue holds one whole level.","So `len(queue)` at the start of a round is the number of nodes on that level. Keep the greatest one you see.","Start `best` at 0 and put the root in the queue only when it isn't `None`, so the empty tree gives 0."],"tests":[{"name":"Test 1","stdin":"","call":"root = Node(8, Node(3, Node(1), Node(6)), Node(12, None, Node(15)))\nprint(widest(root))\nprint(widest(Node(5, Node(4, Node(3)))))\n","expect":"3\n1","hidden":false},{"name":"widest(None)","stdin":"","call":"widest(None)\n","expect":"0","hidden":true,"returns":true},{"name":"widest(Node(1))","stdin":"","call":"widest(Node(1))\n","expect":"1","hidden":true,"returns":true},{"name":"widest(Node(1, Node(2, Node(4), Node(5)), Node(3, Node(6), Node(7, Node(8)))))","stdin":"","call":"widest(Node(1, Node(2, Node(4), Node(5)), Node(3, Node(6), Node(7, Node(8)))))\n","expect":"4","hidden":true,"returns":true},{"name":"widest(Node(1, Node(2, Node(4, Node(8), Node(9))), Node(3, None, Node(7, Node(10), Node(11)))))","stdin":"","call":"widest(Node(1, Node(2, Node(4, Node(8), Node(9))), Node(3, None, Node(7, Node(10), Node(11)))))\n","expect":"4","hidden":true,"returns":true},{"name":"Test 6","stdin":"","call":"root = None\nfor value in range(3000):\n    root = Node(value, root)\nprint(widest(root))\n","expect":"1","hidden":true}],"require":[],"forbid":[]},{"task":"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.\n\nFor example, this program:\n\n```python\n#        1\n#       / \\\n#      2   3\n#       \\\n#        5\nroot = Node(1, Node(2, None, Node(5)), Node(3))\nprint(right_view(root))\n```\n\nprints:\n\n```\n[1, 3, 5]\n```\n","kind":"code","seed":"from collections import deque\n\n\nclass Node:\n    def __init__(self, value, left=None, right=None):\n        self.value = value\n        self.left = left\n        self.right = right\n\n\ndef right_view(root):\n    pass\n\n\nif __name__ == \"__main__\":\n    root = Node(1, Node(2, None, Node(5)), Node(3))\n    print(right_view(root))\n","solution":"from collections import deque\n\n\nclass Node:\n    def __init__(self, value, left=None, right=None):\n        self.value = value\n        self.left = left\n        self.right = right\n\n\ndef right_view(root):\n    view = []\n    queue = deque()\n    if root is not None:\n        queue.append(root)\n    while queue:\n        view.append(queue[-1].value)\n        for _ in range(len(queue)):\n            node = queue.popleft()\n            if node.left is not None:\n                queue.append(node.left)\n            if node.right is not None:\n                queue.append(node.right)\n    return view\n\n\nif __name__ == \"__main__\":\n    root = Node(1, Node(2, None, Node(5)), Node(3))\n    print(right_view(root))\n","hints":["Go level by level, as the lesson's `levels` does. The value you want from each level is its last one.","At the start of a round, the queue holds one whole level from left to right, so its last node, `queue[-1]`, is the rightmost one. Or keep the last node you pop in the `for` loop.","An empty tree gives an empty list: put the root in the queue only when it isn't `None`."],"tests":[{"name":"Test 1","stdin":"","call":"root = Node(1, Node(2, None, Node(5)), Node(3))\nprint(right_view(root))\n","expect":"[1, 3, 5]","hidden":false},{"name":"right_view(None)","stdin":"","call":"right_view(None)\n","expect":"[]","hidden":true,"returns":true},{"name":"right_view(Node(8, Node(3, Node(1), Node(6)), Node(12, None, Node(15))))","stdin":"","call":"right_view(Node(8, Node(3, Node(1), Node(6)), Node(12, None, Node(15))))\n","expect":"[8, 12, 15]","hidden":true,"returns":true},{"name":"right_view(Node(1, Node(2, Node(4))))","stdin":"","call":"right_view(Node(1, Node(2, Node(4))))\n","expect":"[1, 2, 4]","hidden":true,"returns":true},{"name":"right_view(Node(1, Node(2, Node(4, Node(7))), Node(3, Node(5), Node(6))))","stdin":"","call":"right_view(Node(1, Node(2, Node(4, Node(7))), Node(3, Node(5), Node(6))))\n","expect":"[1, 3, 6, 7]","hidden":true,"returns":true},{"name":"Test 6","stdin":"","call":"root = None\nfor value in range(3000):\n    if value % 2 == 0:\n        root = Node(value, root)\n    else:\n        root = Node(value, None, root)\nview = right_view(root)\nprint(len(view), view[:3], view[-1])\n","expect":"3000 [2999, 2998, 2997] 0","hidden":true}],"require":[],"forbid":[]}]}