{"id":"linked-structures-search-trees","slug":"binary-search-trees","title":"Binary search trees","text":"A list's nodes have one link each. A **tree**'s nodes can have several. In a **binary tree**, each node has two links, `left` and `right`, either of which can be `null`. The top node is the **root**, and a node with no children is a **leaf**. A node's left link leads to its **left subtree**: that node and everything under it.\n\n### The search tree rule\n\nA **binary search tree** keeps one rule at every node: everything in its left subtree is smaller than the node's value, and everything in its right subtree is bigger. Adding 50, 30, 70, 20, 40 and 60, in that order, gives this tree:\n\n```text\n        50\n       /  \\\n     30    70\n    /  \\   /\n  20   40 60\n```\n\nTo find 40, start at the root: 40 is smaller than 50, so go left; bigger than 30, so go right; there it is. Each comparison goes one level down and skips a whole subtree, so a search visits at most one node per level. A value that isn't in the tree is found missing the same way, when the next link to follow is `null`. Ten levels can hold up to 1,023 values, so a tree of 1,000 values with a good shape needs only 10 comparisons to find any of them.\n\nThe shape depends on the order the values come in. Added in sorted order, 20, 30, 40, 50 and so on, each value goes to the right of the one before, and the tree is a chain as long as a linked list. Java's TreeMap (step 6) avoids that: its tree rebalances itself as values are added (it's a kind called a red-black tree).\n\n### Adding, recursively\n\nA tree is made of smaller trees, so recursion (module 55) fits it well. To add a value to a subtree: if the subtree is empty (`null`), the result is a new node; otherwise add it to the left or the right subtree, whichever the rule says, and the node stays where it was:\n\n```java\npublic class Main {\n    public static void main(String[] args) {\n        NumberTree tree = new NumberTree();\n        int[] values = {50, 30, 70, 20, 40, 60, 40};\n        for (int value : values) {\n            tree.add(value);\n        }\n        System.out.println(tree.size() + \" values\");\n        System.out.println(\"Sum \" + tree.sum());\n    }\n}\n// ==== NumberTree.java ====\npublic class NumberTree {\n    private NumberNode root;\n\n    public void add(int value) {\n        this.root = add(this.root, value);\n    }\n\n    private NumberNode add(NumberNode node, int value) {\n        if (node == null) {\n            return new NumberNode(value);\n        }\n        if (value < node.value) {\n            node.left = add(node.left, value);\n        } else if (value > node.value) {\n            node.right = add(node.right, value);\n        }\n        return node;\n    }\n\n    public int size() {\n        return size(this.root);\n    }\n\n    private int size(NumberNode node) {\n        if (node == null) {\n            return 0;\n        }\n        return size(node.left) + 1 + size(node.right);\n    }\n\n    public int sum() {\n        return sum(this.root);\n    }\n\n    private int sum(NumberNode node) {\n        if (node == null) {\n            return 0;\n        }\n        return sum(node.left) + node.value + sum(node.right);\n    }\n}\n// ==== NumberNode.java ====\npublic class NumberNode {\n    int value;\n    NumberNode left;\n    NumberNode right;\n\n    public NumberNode(int value) {\n        this.value = value;\n        this.left = null;\n        this.right = null;\n    }\n}\n```\n\n```output\n6 values\nSum 270\n```\n\n- Each public method calls a private helper of the same name that takes a node: the helper does the work on a subtree, and the public method starts it at the root. Code that uses the tree never sees a node.\n- The recursive `add` returns the subtree's root. For an empty subtree, that's the new node, and `node.left = add(node.left, value);` links it in; for any other subtree, it's the node that was there, so the assignment changes nothing.\n- The second 40 is neither smaller nor bigger than the 40 in the tree, so this tree ignores it, like a set.\n- `size` and `sum` visit every node: the empty tree is the base case, and a tree is its left subtree, its root and its right subtree.\n- Each call goes one level down, so the depth of the recursion is the height of the tree. Keep that in mind for a tree that's a long chain.\n\n### Visiting in order\n\n`sum` adds the left subtree, then the node, then the right subtree. Visiting the nodes in that order, left, node, right, is called an **in-order** walk, and in a search tree it visits the values from smallest to biggest: everything left of a node is smaller, and everything right of it bigger. Printing the values on such a walk prints them sorted.\n\nStrings are compared with `compareTo` (module 38): `word.compareTo(node.word)` is negative when `word` comes first in alphabetical order, positive when it comes after, and 0 when they're equal.\n","task":"A glossary keeps its words in a binary search tree. In `WordTree.java`, write `add(String word)`, which adds a word with the search tree rule, comparing with `compareTo`. A word that's already in the tree is ignored. You can write it recursively, like NumberTree, or with a loop. The class already has `printShape()`, which prints the tree with each child under its parent, indented and marked `L:` or `R:`. The check runs:\n\n```java\nWordTree glossary = new WordTree();\nglossary.add(\"loop\");\nglossary.add(\"array\");\nglossary.add(\"method\");\nglossary.add(\"class\");\nglossary.add(\"variable\");\nglossary.add(\"array\");\nglossary.printShape();\n```\n\nand expects:\n\n```\nloop\n  L: array\n    R: class\n  R: method\n    R: variable\n```\n","kind":"code","seed":"// ==== WordTree.java ====\npublic class WordTree {\n    private WordNode root;\n\n    public void add(String word) {\n\n    }\n\n    public void printShape() {\n        printShape(this.root, \"\", \"\");\n    }\n\n    private void printShape(WordNode node, String indent, String label) {\n        if (node == null) {\n            return;\n        }\n        System.out.println(indent + label + node.word);\n        printShape(node.left, indent + \"  \", \"L: \");\n        printShape(node.right, indent + \"  \", \"R: \");\n    }\n}\n\n// ==== WordNode.java ====\npublic class WordNode {\n    String word;\n    WordNode left;\n    WordNode right;\n\n    public WordNode(String word) {\n        this.word = word;\n        this.left = null;\n        this.right = null;\n    }\n}\n\n// ==== Main.java ====\npublic class Main {\n    public static void main(String[] args) {\n        WordTree glossary = new WordTree();\n        glossary.add(\"loop\");\n        glossary.add(\"array\");\n        glossary.add(\"method\");\n        glossary.add(\"class\");\n        glossary.add(\"variable\");\n        glossary.add(\"array\");\n        glossary.printShape();\n    }\n}\n","solution":"// ==== WordTree.java ====\npublic class WordTree {\n    private WordNode root;\n\n    public void add(String word) {\n        this.root = add(this.root, word);\n    }\n\n    private WordNode add(WordNode node, String word) {\n        if (node == null) {\n            return new WordNode(word);\n        }\n        int comparison = word.compareTo(node.word);\n        if (comparison < 0) {\n            node.left = add(node.left, word);\n        } else if (comparison > 0) {\n            node.right = add(node.right, word);\n        }\n        return node;\n    }\n\n    public void printShape() {\n        printShape(this.root, \"\", \"\");\n    }\n\n    private void printShape(WordNode node, String indent, String label) {\n        if (node == null) {\n            return;\n        }\n        System.out.println(indent + label + node.word);\n        printShape(node.left, indent + \"  \", \"L: \");\n        printShape(node.right, indent + \"  \", \"R: \");\n    }\n}\n\n// ==== WordNode.java ====\npublic class WordNode {\n    String word;\n    WordNode left;\n    WordNode right;\n\n    public WordNode(String word) {\n        this.word = word;\n        this.left = null;\n        this.right = null;\n    }\n}\n\n// ==== Main.java ====\npublic class Main {\n    public static void main(String[] args) {\n        WordTree glossary = new WordTree();\n        glossary.add(\"loop\");\n        glossary.add(\"array\");\n        glossary.add(\"method\");\n        glossary.add(\"class\");\n        glossary.add(\"variable\");\n        glossary.add(\"array\");\n        glossary.printShape();\n    }\n}\n","hints":["Follow NumberTree: `add(String word)` sets `this.root = add(this.root, word);`, and a private helper `add(WordNode node, String word)` returns `new WordNode(word)` when `node` is `null`.","Otherwise compare: `int comparison = word.compareTo(node.word);`. Below 0, `node.left = add(node.left, word);`; above 0, the same on the right; at 0, nothing. Return `node`."],"tests":[{"name":"Test 1","stdin":"","call":"WordTree glossary = new WordTree();\nglossary.add(\"loop\");\nglossary.add(\"array\");\nglossary.add(\"method\");\nglossary.add(\"class\");\nglossary.add(\"variable\");\nglossary.add(\"array\");\nglossary.printShape();\n","expect":"loop\n  L: array\n    R: class\n  R: method\n    R: variable","hidden":false},{"name":"Test 2","stdin":"","call":"WordTree tree = new WordTree();\ntree.add(\"cat\");\ntree.printShape();\nString[] words = {\"ant\", \"bee\", \"cow\", \"dog\", \"eel\"};\nWordTree chain = new WordTree();\nfor (String word : words) {\n    chain.add(word);\n}\nchain.printShape();\n","expect":"cat\nant\n  R: bee\n    R: cow\n      R: dog\n        R: eel","hidden":true},{"name":"Test 3","stdin":"","call":"WordTree tree = new WordTree();\nString[] words = {\"mango\", \"fig\", \"pear\", \"apple\", \"grape\", \"kiwi\", \"plum\", \"date\", \"fig\", \"nut\"};\nfor (String word : words) {\n    tree.add(word);\n}\ntree.printShape();\n","expect":"mango\n  L: fig\n    L: apple\n      R: date\n    R: grape\n      R: kiwi\n  R: pear\n    L: nut\n    R: plum","hidden":true}],"require":[],"forbid":[],"more":[{"task":"Give `WordTree` the method `contains(String word)`, which returns `true` when the word is in the tree. Use the search tree rule: from the root, go left or right at each node, so that it visits at most one node on each level. A loop or recursion both work. The check runs:\n\n```java\nWordTree glossary = new WordTree();\nString[] words = {\"loop\", \"array\", \"method\", \"class\", \"variable\"};\nfor (String word : words) {\n    glossary.add(word);\n}\nSystem.out.println(glossary.contains(\"class\"));\nSystem.out.println(glossary.contains(\"variable\"));\nSystem.out.println(glossary.contains(\"string\"));\nSystem.out.println(new WordTree().contains(\"loop\"));\n```\n\nand expects:\n\n```\ntrue\ntrue\nfalse\nfalse\n```\n","kind":"code","seed":"// ==== WordTree.java ====\npublic class WordTree {\n    private WordNode root;\n\n    public void add(String word) {\n        this.root = add(this.root, word);\n    }\n\n    private WordNode add(WordNode node, String word) {\n        if (node == null) {\n            return new WordNode(word);\n        }\n        int comparison = word.compareTo(node.word);\n        if (comparison < 0) {\n            node.left = add(node.left, word);\n        } else if (comparison > 0) {\n            node.right = add(node.right, word);\n        }\n        return node;\n    }\n\n    public boolean contains(String word) {\n        return false;\n    }\n}\n\n// ==== WordNode.java ====\npublic class WordNode {\n    String word;\n    WordNode left;\n    WordNode right;\n\n    public WordNode(String word) {\n        this.word = word;\n        this.left = null;\n        this.right = null;\n    }\n}\n\n// ==== Main.java ====\npublic class Main {\n    public static void main(String[] args) {\n        WordTree glossary = new WordTree();\n        String[] words = {\"loop\", \"array\", \"method\", \"class\", \"variable\"};\n        for (String word : words) {\n            glossary.add(word);\n        }\n        System.out.println(glossary.contains(\"class\"));\n        System.out.println(glossary.contains(\"variable\"));\n        System.out.println(glossary.contains(\"string\"));\n        System.out.println(new WordTree().contains(\"loop\"));\n    }\n}\n","solution":"// ==== WordTree.java ====\npublic class WordTree {\n    private WordNode root;\n\n    public void add(String word) {\n        this.root = add(this.root, word);\n    }\n\n    private WordNode add(WordNode node, String word) {\n        if (node == null) {\n            return new WordNode(word);\n        }\n        int comparison = word.compareTo(node.word);\n        if (comparison < 0) {\n            node.left = add(node.left, word);\n        } else if (comparison > 0) {\n            node.right = add(node.right, word);\n        }\n        return node;\n    }\n\n    public boolean contains(String word) {\n        WordNode current = this.root;\n        while (current != null) {\n            int comparison = word.compareTo(current.word);\n            if (comparison == 0) {\n                return true;\n            }\n            if (comparison < 0) {\n                current = current.left;\n            } else {\n                current = current.right;\n            }\n        }\n        return false;\n    }\n}\n\n// ==== WordNode.java ====\npublic class WordNode {\n    String word;\n    WordNode left;\n    WordNode right;\n\n    public WordNode(String word) {\n        this.word = word;\n        this.left = null;\n        this.right = null;\n    }\n}\n\n// ==== Main.java ====\npublic class Main {\n    public static void main(String[] args) {\n        WordTree glossary = new WordTree();\n        String[] words = {\"loop\", \"array\", \"method\", \"class\", \"variable\"};\n        for (String word : words) {\n            glossary.add(word);\n        }\n        System.out.println(glossary.contains(\"class\"));\n        System.out.println(glossary.contains(\"variable\"));\n        System.out.println(glossary.contains(\"string\"));\n        System.out.println(new WordTree().contains(\"loop\"));\n    }\n}\n","hints":["With a loop: a variable `current` starts at `this.root`. While it isn't `null`, compare the word with `current.word`: equal means found, smaller means `current = current.left;`, bigger means `current = current.right;`.","Falling off the tree (`current` becomes `null`) means the word isn't there: `return false;` after the loop."],"tests":[{"name":"Test 1","stdin":"","call":"WordTree glossary = new WordTree();\nString[] words = {\"loop\", \"array\", \"method\", \"class\", \"variable\"};\nfor (String word : words) {\n    glossary.add(word);\n}\nSystem.out.println(glossary.contains(\"class\"));\nSystem.out.println(glossary.contains(\"variable\"));\nSystem.out.println(glossary.contains(\"string\"));\nSystem.out.println(new WordTree().contains(\"loop\"));\n","expect":"true\ntrue\nfalse\nfalse","hidden":false},{"name":"Test 2","stdin":"","call":"WordTree tree = new WordTree();\nString[] words = {\"mango\", \"fig\", \"pear\", \"apple\", \"grape\", \"kiwi\", \"plum\", \"date\", \"nut\"};\nfor (String word : words) {\n    tree.add(word);\n}\nString[] asked = {\"mango\", \"apple\", \"kiwi\", \"nut\", \"plum\", \"banana\", \"zucchini\", \"lime\", \"Mango\", \"dat\"};\nfor (String word : asked) {\n    System.out.println(word + \" \" + tree.contains(word));\n}\n","expect":"mango true\napple true\nkiwi true\nnut true\nplum true\nbanana false\nzucchini false\nlime false\nMango false\ndat false","hidden":true}],"require":[],"forbid":[]},{"task":"Give `WordTree` the method `printInOrder()`, which prints every word of the tree in alphabetical order, one per line, with an in-order walk: the left subtree, the node, the right subtree. Don't sort anything: the tree's order is enough. An empty tree prints nothing. The check runs:\n\n```java\nWordTree glossary = new WordTree();\nString[] words = {\"loop\", \"array\", \"method\", \"class\", \"variable\", \"string\"};\nfor (String word : words) {\n    glossary.add(word);\n}\nglossary.printInOrder();\n```\n\nand expects:\n\n```\narray\nclass\nloop\nmethod\nstring\nvariable\n```\n","kind":"code","seed":"// ==== WordTree.java ====\npublic class WordTree {\n    private WordNode root;\n\n    public void add(String word) {\n        this.root = add(this.root, word);\n    }\n\n    private WordNode add(WordNode node, String word) {\n        if (node == null) {\n            return new WordNode(word);\n        }\n        int comparison = word.compareTo(node.word);\n        if (comparison < 0) {\n            node.left = add(node.left, word);\n        } else if (comparison > 0) {\n            node.right = add(node.right, word);\n        }\n        return node;\n    }\n\n    public void printInOrder() {\n\n    }\n}\n\n// ==== WordNode.java ====\npublic class WordNode {\n    String word;\n    WordNode left;\n    WordNode right;\n\n    public WordNode(String word) {\n        this.word = word;\n        this.left = null;\n        this.right = null;\n    }\n}\n\n// ==== Main.java ====\npublic class Main {\n    public static void main(String[] args) {\n        WordTree glossary = new WordTree();\n        String[] words = {\"loop\", \"array\", \"method\", \"class\", \"variable\", \"string\"};\n        for (String word : words) {\n            glossary.add(word);\n        }\n        glossary.printInOrder();\n    }\n}\n","solution":"// ==== WordTree.java ====\npublic class WordTree {\n    private WordNode root;\n\n    public void add(String word) {\n        this.root = add(this.root, word);\n    }\n\n    private WordNode add(WordNode node, String word) {\n        if (node == null) {\n            return new WordNode(word);\n        }\n        int comparison = word.compareTo(node.word);\n        if (comparison < 0) {\n            node.left = add(node.left, word);\n        } else if (comparison > 0) {\n            node.right = add(node.right, word);\n        }\n        return node;\n    }\n\n    public void printInOrder() {\n        printInOrder(this.root);\n    }\n\n    private void printInOrder(WordNode node) {\n        if (node == null) {\n            return;\n        }\n        printInOrder(node.left);\n        System.out.println(node.word);\n        printInOrder(node.right);\n    }\n}\n\n// ==== WordNode.java ====\npublic class WordNode {\n    String word;\n    WordNode left;\n    WordNode right;\n\n    public WordNode(String word) {\n        this.word = word;\n        this.left = null;\n        this.right = null;\n    }\n}\n\n// ==== Main.java ====\npublic class Main {\n    public static void main(String[] args) {\n        WordTree glossary = new WordTree();\n        String[] words = {\"loop\", \"array\", \"method\", \"class\", \"variable\", \"string\"};\n        for (String word : words) {\n            glossary.add(word);\n        }\n        glossary.printInOrder();\n    }\n}\n","hints":["Write a private helper `printInOrder(WordNode node)`, and have the public method call it with `this.root`. The helper's base case is an empty subtree: `if (node == null) { return; }`.","Otherwise it prints the left subtree with a recursive call, then `node.word`, then the right subtree."],"tests":[{"name":"Test 1","stdin":"","call":"WordTree glossary = new WordTree();\nString[] words = {\"loop\", \"array\", \"method\", \"class\", \"variable\", \"string\"};\nfor (String word : words) {\n    glossary.add(word);\n}\nglossary.printInOrder();\n","expect":"array\nclass\nloop\nmethod\nstring\nvariable","hidden":false},{"name":"Test 2","stdin":"","call":"WordTree empty = new WordTree();\nempty.printInOrder();\nWordTree tree = new WordTree();\nString[] words = {\"mango\", \"fig\", \"pear\", \"apple\", \"grape\", \"kiwi\", \"plum\", \"date\", \"fig\", \"nut\"};\nfor (String word : words) {\n    tree.add(word);\n}\ntree.printInOrder();\n","expect":"apple\ndate\nfig\ngrape\nkiwi\nmango\nnut\npear\nplum","hidden":true},{"name":"Test 3","stdin":"","call":"WordTree chain = new WordTree();\nString[] words = {\"zebra\", \"yak\", \"wolf\", \"vole\"};\nfor (String word : words) {\n    chain.add(word);\n}\nchain.printInOrder();\n","expect":"vole\nwolf\nyak\nzebra","hidden":true}],"require":[],"forbid":[{"pattern":"\\b(sort|sorted|TreeSet|TreeMap)\\b","message":"Don't sort: an in-order walk of the tree visits the words in order already."}]}]}