{"id":"recursion-examples-sorted-tree","slug":"sorted-tree","title":"A sorted binary tree","text":"In the trees so far, a value could be anywhere, so a search had to visit every node. A **sorted binary tree** (also called a binary search tree) keeps its values in order. Everything in a node's left subtree is smaller than the node's value, and everything in its right subtree is greater:\n\n```text\n         50\n       /    \\\n     30      70\n    /  \\    /  \\\n  20   40  60   80\n```\n\n### Searching\n\nThe order makes searching fast, in the same way as binary search. Compare the value you're looking for with the node's value. If it's smaller, it can only be in the left subtree, and if it's greater, only in the right one. So the search goes down one path and never needs the other side:\n\n```python\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 find(node, value):\n    if node is None:\n        return False\n    if value == node.value:\n        return True\n    if value < node.value:\n        return find(node.left, value)\n    return find(node.right, value)\n\n\ntree = Node(50, Node(30, Node(20), Node(40)), Node(70, Node(60), Node(80)))\nprint(find(tree, 60))\nprint(find(tree, 65))\n```\n\n```output\nTrue\nFalse\n```\n\nThe search for 65 goes from 50 to the right, from 70 to the left, and from 60 to the right, where there's nothing: `None` gives `False`. It looked at three nodes out of seven. In a tree with a million values whose branches are about equally deep, it would look at about twenty.\n\n### Adding values\n\nTo add a value, go down the same path as a search. When the way on is `None`, that's the place for the new node:\n\n```python\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 add(node, value):\n    if value < node.value:\n        if node.left is None:\n            node.left = Node(value)\n        else:\n            add(node.left, value)\n    elif value > node.value:\n        if node.right is None:\n            node.right = Node(value)\n        else:\n            add(node.right, value)\n\n\ndef print_in_order(node):\n    if node is not None:\n        print_in_order(node.left)\n        print(node.value)\n        print_in_order(node.right)\n\n\ntree = Node(42)\nfor value in [17, 99, 8, 23, 61, 23]:\n    add(tree, value)\nprint_in_order(tree)\n```\n\n```output\n8\n17\n23\n42\n61\n99\n```\n\nA value that's already in the tree is neither smaller nor greater than the node that holds it, so neither branch adds it again: the second 23 is left out.\n\n`print_in_order` visits the left subtree first, then the node, and then the right subtree. In a sorted tree, everything on the left is smaller and everything on the right is greater, so the values come out in increasing order.\n\nThe shape of the tree depends on the order the values are added in. Adding values that are already sorted, such as 1, 2, 3, 4, makes every new node a right child, and the \"tree\" becomes one long line. Searching it is then no faster than going through a list.\n","task":"Fill in the blanks so the search goes into the correct subtree. The program should print:\n\n```\nTrue\nFalse\nTrue\n```\n","kind":"fill","seed":"class 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 find(node, value):\n    if node is None:\n        return False\n    if value == node.value:\n        return True\n    if value < node.value:\n        return find([[node.left]], value)\n    return find([[node.right]], value)\n\n\ntree = Node(50, Node(30, Node(20), Node(40)), Node(70, Node(60), Node(80)))\nprint(find(tree, 20))\nprint(find(tree, 75))\nprint(find(tree, 80))\n","solution":"class 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 find(node, value):\n    if node is None:\n        return False\n    if value == node.value:\n        return True\n    if value < node.value:\n        return find(node.left, value)\n    return find(node.right, value)\n\n\ntree = Node(50, Node(30, Node(20), Node(40)), Node(70, Node(60), Node(80)))\nprint(find(tree, 20))\nprint(find(tree, 75))\nprint(find(tree, 80))\n","hints":["Smaller values are always in the left subtree, and greater ones in the right subtree.","The first blank is `node.left` and the second `node.right`."],"tests":[{"name":"Output","stdin":"","expect":"True\nFalse\nTrue","hidden":false}],"require":[],"forbid":[],"more":[{"task":"Write a recursive function `smallest(node)` that returns the smallest value in a sorted binary tree. The tree is never empty. Use the order of the tree: you don't need to look at every node.\n\nFor example, this program:\n\n```python\ntree = Node(50, Node(30, Node(20), Node(40)), Node(70))\nprint(smallest(tree))\n```\n\nprints:\n\n```\n20\n```\n","kind":"code","seed":"class 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 smallest(node):\n    pass\n\n\nif __name__ == \"__main__\":\n    tree = Node(50, Node(30, Node(20), Node(40)), Node(70))\n    print(smallest(tree))\n","solution":"class 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 smallest(node):\n    if node.left is None:\n        return node.value\n    return smallest(node.left)\n\n\nif __name__ == \"__main__\":\n    tree = Node(50, Node(30, Node(20), Node(40)), Node(70))\n    print(smallest(tree))\n","hints":["In a sorted tree, the smaller values are always on the left. Where is the smallest one, then?","Keep going left. A node with no left child holds the smallest value of its subtree: that's the base case.","Otherwise, the answer is `smallest(node.left)`."],"tests":[{"name":"Test 1","stdin":"","call":"tree = Node(50, Node(30, Node(20), Node(40)), Node(70))\nprint(smallest(tree))\n","expect":"20","hidden":false},{"name":"smallest(Node(5))","stdin":"","call":"smallest(Node(5))\n","expect":"5","hidden":true,"returns":true},{"name":"smallest(Node(5, None, Node(9)))","stdin":"","call":"smallest(Node(5, None, Node(9)))\n","expect":"5","hidden":true,"returns":true},{"name":"smallest(Node(10, Node(4, None, Node(6)), Node(12)))","stdin":"","call":"smallest(Node(10, Node(4, None, Node(6)), Node(12)))\n","expect":"4","hidden":true,"returns":true}],"require":[{"pattern":"def smallest\\b[^\\n]*\\n(?:[ \\t]*\\n|[ \\t]+[^\\n]*\\n)*?[ \\t]+[^\\n]*\\bsmallest\\s*\\(","message":"Make `smallest` call itself inside its own body."}],"forbid":[{"pattern":"\\b(?:while|for)\\b","message":"Use recursion instead of a loop."}]},{"task":"Write a recursive function `in_order(node)` that returns a list of all the values in a sorted binary tree, in increasing order. An empty tree, `None`, gives an empty list.\n\nFor example, this program:\n\n```python\ntree = Node(50, Node(30, Node(20), Node(40)), Node(70, Node(60), Node(80)))\nprint(in_order(tree))\n```\n\nprints:\n\n```\n[20, 30, 40, 50, 60, 70, 80]\n```\n","kind":"code","seed":"class 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 in_order(node):\n    pass\n\n\nif __name__ == \"__main__\":\n    tree = Node(50, Node(30, Node(20), Node(40)), Node(70, Node(60), Node(80)))\n    print(in_order(tree))\n","solution":"class 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 in_order(node):\n    if node is None:\n        return []\n    return in_order(node.left) + [node.value] + in_order(node.right)\n\n\nif __name__ == \"__main__\":\n    tree = Node(50, Node(30, Node(20), Node(40)), Node(70, Node(60), Node(80)))\n    print(in_order(tree))\n","hints":["The base case is the empty tree, which gives `[]`.","The values of the left subtree come first, then the node's own value, then the values of the right subtree.","Lists can be joined with `+`: `in_order(node.left) + [node.value] + in_order(node.right)`."],"tests":[{"name":"Test 1","stdin":"","call":"tree = Node(50, Node(30, Node(20), Node(40)), Node(70, Node(60), Node(80)))\nprint(in_order(tree))\n","expect":"[20, 30, 40, 50, 60, 70, 80]","hidden":false},{"name":"in_order(None)","stdin":"","call":"in_order(None)\n","expect":"[]","hidden":true,"returns":true},{"name":"in_order(Node(1, None, Node(2, None, Node(3))))","stdin":"","call":"in_order(Node(1, None, Node(2, None, Node(3))))\n","expect":"[1, 2, 3]","hidden":true,"returns":true},{"name":"in_order(Node(10, Node(5, Node(1), Node(7)), Node(15)))","stdin":"","call":"in_order(Node(10, Node(5, Node(1), Node(7)), Node(15)))\n","expect":"[1, 5, 7, 10, 15]","hidden":true,"returns":true}],"require":[{"pattern":"def in_order\\b[^\\n]*\\n(?:[ \\t]*\\n|[ \\t]+[^\\n]*\\n)*?[ \\t]+[^\\n]*\\bin_order\\s*\\(","message":"Make `in_order` call itself inside its own body."}],"forbid":[{"pattern":"\\bsorted\\s*\\(|\\.sort\\s*\\(","message":"Use the order of the tree instead of sorting the values."}]}]}