{"id":"linked-structures-nodes","slug":"nodes-and-links","title":"Nodes and links","text":"This module is an extra: the MOOC doesn't cover it. It's about data structures built from small objects that refer to each other: linked lists, stacks, queues and trees. They're worth knowing for three reasons. Java's own collections use them (LinkedList is a chain of such objects, and TreeMap and TreeSet keep their values in a tree). They explain why some operations of a collection take the same few steps however big it is, while others go through every value. And they come up in programming interviews. The module uses recursion (module 55) and `var` (module 57).\n\n### A node\n\nModule 45 built a list on an array: the values sit side by side, and `get(7)` goes straight to place 7 of the array. A **linked list** keeps each value in an object of its own, a **node**, and each node holds a reference to the next node.\n\nA scavenger hunt works the same way. Each clue is at a place, is worth some points, and tells you where the next clue is. Here's a class for one clue:\n\n```java\npublic class Main {\n    public static void main(String[] args) {\n        Clue first = new Clue(\"the mailbox\", 10);\n        Clue second = new Clue(\"the old oak\", 20);\n        Clue third = new Clue(\"the bike shed\", 30);\n        first.next = second;\n        second.next = third;\n\n        System.out.println(first.place);\n        System.out.println(first.next.place);\n        System.out.println(first.next.next.place);\n        System.out.println(third.next);\n    }\n}\n// ==== Clue.java ====\npublic class Clue {\n    String place;\n    int points;\n    Clue next;\n\n    public Clue(String place, int points) {\n        this.place = place;\n        this.points = points;\n        this.next = null;\n    }\n}\n```\n\n```output\nthe mailbox\nthe old oak\nthe bike shed\nnull\n```\n\n- The instance variable `next` has the type `Clue`, the class's own type. A Clue doesn't hold another Clue inside it: `next` holds a reference to one (module 22), or `null` when there's no next clue.\n- `first.next.place` follows one link: `first.next` is the second clue, and `.place` is its place. `first.next.next.place` follows two.\n- The variables of Clue have no access modifier, so they're package-private (module 41): Main, in the same package, reads and sets them directly. Clue is a small helper whose only job is to hold a value and a link. Step 2 hides nodes like it inside a list class, where nothing else can reach them.\n\nThe three clues and their links look like this, with an arrow for each reference:\n\n```text\nfirst             second            third\n[the mailbox] --> [the old oak] --> [the bike shed] --> null\n```\n\n### Walking along the chain\n\nTo go through the hunt, a variable `current` starts at the first clue and moves on with `current = current.next`, until it's `null`:\n\n```java\npublic class Main {\n    public static void main(String[] args) {\n        Clue first = new Clue(\"the mailbox\", 10);\n        first.next = new Clue(\"the old oak\", 20);\n        first.next.next = new Clue(\"the bike shed\", 30);\n\n        int total = 0;\n        Clue current = first;\n        while (current != null) {\n            total += current.points;\n            current = current.next;\n        }\n        System.out.println(\"The hunt is worth \" + total + \" points\");\n        System.out.println(\"It starts at \" + first.place);\n    }\n}\n// ==== Clue.java ====\npublic class Clue {\n    String place;\n    int points;\n    Clue next;\n\n    public Clue(String place, int points) {\n        this.place = place;\n        this.points = points;\n        this.next = null;\n    }\n}\n```\n\n```output\nThe hunt is worth 60 points\nIt starts at the mailbox\n```\n\n`current` is only a reference that moves along the chain. Moving it changes no link, so `first` still refers to the first clue after the loop. The loop stops after the last clue, whose `next` is `null`.\n\n### One step too far\n\nA hunt with no clues at all has no first clue: the variable for it is `null`. This method looks for the place of the last clue, and works for a hunt of one clue, but not for an empty one:\n\n```java\npublic class Main {\n    public static void main(String[] args) {\n        Clue gate = new Clue(\"the gate\", 5);\n        System.out.println(lastPlace(gate));\n        System.out.println(lastPlace(null));\n    }\n\n    public static String lastPlace(Clue first) {\n        Clue current = first;\n        while (current.next != null) {\n            current = current.next;\n        }\n        return current.place;\n    }\n}\n// ==== Clue.java ====\npublic class Clue {\n    String place;\n    int points;\n    Clue next;\n\n    public Clue(String place, int points) {\n        this.place = place;\n        this.points = points;\n        this.next = null;\n    }\n}\n```\n\n```output\nthe gate\n```\n\n```crash\nException in thread \"main\" java.lang.NullPointerException: Cannot read field \"next\" because \"<local1>\" is null\n\tat Main.lastPlace(Main.java:10)\n\tat Main.main(Main.java:5)\n```\n\nThe second call gets `null`, so `current` is `null`, and `current.next` asks a missing object for its `next`. Java's message names the field it tried to read, and the variable that was `null`. Java numbers a method's parameters and variables from 0, here `first` 0 and `current` 1, and when a class is compiled without their names kept, as here, the message gives the number: `<local1>` is `current`. The fix is a check before the loop: `if (first == null) { return \"no clues\"; }`.\n\nEvery loop over nodes has two edges to think about: an empty chain, where the first reference is already `null`, and the last node, whose `next` is `null`.\n","task":"Fill in the blanks so that the hunt goes from the gate to the pond to the red bench, and the loop prints each clue's place and points. The program prints:\n\n```\nthe gate: 5\nthe pond: 15\nthe red bench: 25\n```\n","kind":"fill","seed":"public class Main {\n    public static void main(String[] args) {\n        Clue gate = new Clue(\"the gate\", 5);\n        Clue pond = new Clue(\"the pond\", 15);\n        Clue bench = new Clue(\"the red bench\", 25);\n        gate.next = [[pond]];\n        pond.[[next]] = bench;\n\n        Clue current = gate;\n        while (current [[!=]] null) {\n            System.out.println(current.place + \": \" + current.points);\n            current = [[current.next]];\n        }\n    }\n}\n// ==== Clue.java ====\npublic class Clue {\n    String place;\n    int points;\n    Clue next;\n\n    public Clue(String place, int points) {\n        this.place = place;\n        this.points = points;\n        this.next = null;\n    }\n}\n","solution":"public class Main {\n    public static void main(String[] args) {\n        Clue gate = new Clue(\"the gate\", 5);\n        Clue pond = new Clue(\"the pond\", 15);\n        Clue bench = new Clue(\"the red bench\", 25);\n        gate.next = pond;\n        pond.next = bench;\n\n        Clue current = gate;\n        while (current != null) {\n            System.out.println(current.place + \": \" + current.points);\n            current = current.next;\n        }\n    }\n}\n// ==== Clue.java ====\npublic class Clue {\n    String place;\n    int points;\n    Clue next;\n\n    public Clue(String place, int points) {\n        this.place = place;\n        this.points = points;\n        this.next = null;\n    }\n}\n","hints":["The gate's `next` should refer to the pond, and the pond's `next` to the bench. The bench's `next` stays `null`.","The loop runs while `current` refers to a clue, so the test is `current != null`. Each round moves it one clue on: `current = current.next;`."],"tests":[{"name":"Output","stdin":"","expect":"the gate: 5\nthe pond: 15\nthe red bench: 25","hidden":false}],"require":[],"forbid":[],"more":[{"task":"Write the method `route(Clue first)` in `Main.java`. It returns the places of the hunt in order, each followed by ` -> `, and then the word `finish`. An empty hunt (`first` is `null`) gives just `finish`. Go along the chain with a loop over `next`. The check runs:\n\n```java\nClue gate = new Clue(\"the gate\", 5);\ngate.next = new Clue(\"the pond\", 15);\ngate.next.next = new Clue(\"the red bench\", 25);\nSystem.out.println(route(gate));\nSystem.out.println(route(gate.next.next));\nSystem.out.println(route(null));\n```\n\nand expects:\n\n```\nthe gate -> the pond -> the red bench -> finish\nthe red bench -> finish\nfinish\n```\n","kind":"code","seed":"// ==== Main.java ====\npublic class Main {\n    public static void main(String[] args) {\n        Clue gate = new Clue(\"the gate\", 5);\n        gate.next = new Clue(\"the pond\", 15);\n        gate.next.next = new Clue(\"the red bench\", 25);\n        System.out.println(route(gate));\n        System.out.println(route(gate.next.next));\n        System.out.println(route(null));\n    }\n\n    public static String route(Clue first) {\n        return \"\";\n    }\n}\n\n// ==== Clue.java ====\npublic class Clue {\n    String place;\n    int points;\n    Clue next;\n\n    public Clue(String place, int points) {\n        this.place = place;\n        this.points = points;\n        this.next = null;\n    }\n}\n","solution":"// ==== Main.java ====\npublic class Main {\n    public static void main(String[] args) {\n        Clue gate = new Clue(\"the gate\", 5);\n        gate.next = new Clue(\"the pond\", 15);\n        gate.next.next = new Clue(\"the red bench\", 25);\n        System.out.println(route(gate));\n        System.out.println(route(gate.next.next));\n        System.out.println(route(null));\n    }\n\n    public static String route(Clue first) {\n        String result = \"\";\n        Clue current = first;\n        while (current != null) {\n            result += current.place + \" -> \";\n            current = current.next;\n        }\n        return result + \"finish\";\n    }\n}\n\n// ==== Clue.java ====\npublic class Clue {\n    String place;\n    int points;\n    Clue next;\n\n    public Clue(String place, int points) {\n        this.place = place;\n        this.points = points;\n        this.next = null;\n    }\n}\n","hints":["Start with an empty String and a variable `current` at `first`. While `current` isn't `null`, add its place and ` -> `, and move on.","After the loop, add `finish`. For an empty hunt the loop doesn't run at all, so the result is just `finish`, with no special case needed."],"tests":[{"name":"Test 1","stdin":"","call":"Clue gate = new Clue(\"the gate\", 5);\ngate.next = new Clue(\"the pond\", 15);\ngate.next.next = new Clue(\"the red bench\", 25);\nSystem.out.println(route(gate));\nSystem.out.println(route(gate.next.next));\nSystem.out.println(route(null));\n","expect":"the gate -> the pond -> the red bench -> finish\nthe red bench -> finish\nfinish","hidden":false},{"name":"Test 2","stdin":"","call":"Clue well = new Clue(\"the well\", 8);\nClue barn = new Clue(\"the barn\", 12);\nClue hill = new Clue(\"the hill\", 3);\nClue shop = new Clue(\"the corner shop\", 40);\nwell.next = barn;\nbarn.next = hill;\nhill.next = shop;\nSystem.out.println(route(well));\nSystem.out.println(route(barn));\nSystem.out.println(route(shop));\n","expect":"the well -> the barn -> the hill -> the corner shop -> finish\nthe barn -> the hill -> the corner shop -> finish\nthe corner shop -> finish","hidden":true}],"require":[],"forbid":[]},{"task":"Write two methods in `Main.java`:\n\n- `count(Clue first)` returns how many clues the hunt has (0 for an empty hunt);\n- `best(Clue first)` returns the clue worth the most points. When two clues tie, it returns the first of them. For an empty hunt it returns `null`.\n\nThe check runs:\n\n```java\nClue well = new Clue(\"the well\", 8);\nwell.next = new Clue(\"the barn\", 30);\nwell.next.next = new Clue(\"the hill\", 12);\nwell.next.next.next = new Clue(\"the shop\", 30);\nSystem.out.println(count(well) + \" clues\");\nSystem.out.println(\"Best: \" + best(well).place);\nSystem.out.println(count(null) + \" clues\");\nSystem.out.println(best(null) == null);\n```\n\nand expects:\n\n```\n4 clues\nBest: the barn\n0 clues\ntrue\n```\n","kind":"code","seed":"// ==== Main.java ====\npublic class Main {\n    public static void main(String[] args) {\n        Clue well = new Clue(\"the well\", 8);\n        well.next = new Clue(\"the barn\", 30);\n        well.next.next = new Clue(\"the hill\", 12);\n        well.next.next.next = new Clue(\"the shop\", 30);\n        System.out.println(count(well) + \" clues\");\n        System.out.println(\"Best: \" + best(well).place);\n        System.out.println(count(null) + \" clues\");\n        System.out.println(best(null) == null);\n    }\n\n    public static int count(Clue first) {\n        return 0;\n    }\n\n    public static Clue best(Clue first) {\n        return first;\n    }\n}\n\n// ==== Clue.java ====\npublic class Clue {\n    String place;\n    int points;\n    Clue next;\n\n    public Clue(String place, int points) {\n        this.place = place;\n        this.points = points;\n        this.next = null;\n    }\n}\n","solution":"// ==== Main.java ====\npublic class Main {\n    public static void main(String[] args) {\n        Clue well = new Clue(\"the well\", 8);\n        well.next = new Clue(\"the barn\", 30);\n        well.next.next = new Clue(\"the hill\", 12);\n        well.next.next.next = new Clue(\"the shop\", 30);\n        System.out.println(count(well) + \" clues\");\n        System.out.println(\"Best: \" + best(well).place);\n        System.out.println(count(null) + \" clues\");\n        System.out.println(best(null) == null);\n    }\n\n    public static int count(Clue first) {\n        int count = 0;\n        Clue current = first;\n        while (current != null) {\n            count++;\n            current = current.next;\n        }\n        return count;\n    }\n\n    public static Clue best(Clue first) {\n        Clue best = first;\n        Clue current = first;\n        while (current != null) {\n            if (current.points > best.points) {\n                best = current;\n            }\n            current = current.next;\n        }\n        return best;\n    }\n}\n\n// ==== Clue.java ====\npublic class Clue {\n    String place;\n    int points;\n    Clue next;\n\n    public Clue(String place, int points) {\n        this.place = place;\n        this.points = points;\n        this.next = null;\n    }\n}\n","hints":["`count` is the walking loop of the lesson with a counter in place of the sum.","In `best`, keep the best clue so far in a variable that starts at `first` (which is `null` for an empty hunt, the right answer then). Replace it only when a clue has strictly more points, so that the first of a tie stays."],"tests":[{"name":"Test 1","stdin":"","call":"Clue well = new Clue(\"the well\", 8);\nwell.next = new Clue(\"the barn\", 30);\nwell.next.next = new Clue(\"the hill\", 12);\nwell.next.next.next = new Clue(\"the shop\", 30);\nSystem.out.println(count(well) + \" clues\");\nSystem.out.println(\"Best: \" + best(well).place);\nSystem.out.println(count(null) + \" clues\");\nSystem.out.println(best(null) == null);\n","expect":"4 clues\nBest: the barn\n0 clues\ntrue","hidden":false},{"name":"Test 2","stdin":"","call":"Clue only = new Clue(\"the gate\", 5);\nSystem.out.println(count(only) + \" \" + best(only).place);\nClue a = new Clue(\"the pier\", 2);\na.next = new Clue(\"the lighthouse\", 7);\na.next.next = new Clue(\"the dunes\", 9);\na.next.next.next = new Clue(\"the cafe\", 1);\na.next.next.next.next = new Clue(\"the boathouse\", 9);\nSystem.out.println(count(a) + \" \" + best(a).place);\nSystem.out.println(count(a.next.next.next) + \" \" + best(a.next.next.next).place);\n","expect":"1 the gate\n5 the dunes\n2 the boathouse","hidden":true},{"name":"Test 3","stdin":"","call":"Clue a = new Clue(\"the tower\", -3);\na.next = new Clue(\"the stairs\", -1);\na.next.next = new Clue(\"the cellar\", -5);\nSystem.out.println(count(a) + \" \" + best(a).place);\n","expect":"3 the stairs","hidden":true}],"require":[],"forbid":[]}]}