{"id":"sorting-searching-linear-search","slug":"linear-search","title":"Linear search","text":"The second problem of this module is searching: where in the array is a given value, if it's there at all? The simplest algorithm looks at the elements one at a time, from the first to the last, and stops at the first match. It's called **linear search**, since it goes through the elements in a line. You've written it before (module 15). Here it is as a method that returns the index of the value, or -1 when the value isn't there. -1 is never an index, so the caller can tell the two answers apart.\n\nA raffle keeps the numbers of the tickets it has sold in an array:\n\n```java\npublic class Main {\n    public static void main(String[] args) {\n        int[] tickets = {512, 87, 340, 19, 777, 203};\n        System.out.println(positionOf(tickets, 340));\n        System.out.println(positionOf(tickets, 5));\n    }\n\n    public static int positionOf(int[] tickets, int wanted) {\n        for (int i = 0; i < tickets.length; i++) {\n            if (tickets[i] == wanted) {\n                return i;\n            }\n        }\n        return -1;\n    }\n}\n```\n\n```output\n2\n-1\n```\n\n- `return i;` ends the method at the first match, loop and all. There's no need to look further.\n- `return -1;` comes *after* the loop. Only when every element has been looked at, and none matched, is it clear that the value isn't there.\n- The array doesn't need to be in any order. Linear search works on any array or list.\n\n### How much work is it?\n\nCount the values the search looks at. Each look is one comparison, `tickets[i] == wanted`. Finding 340 at index 2 took 3 looks, at indexes 0, 1 and 2. A value at index `i` takes `i + 1` looks. A value that isn't there takes a look at every element, since the search can't stop early.\n\n| Array size | Values looked at, at most |\n| --- | --- |\n| 6 | 6 |\n| 1,000 | 1,000 |\n| 1,000,000 | 1,000,000 |\n\nThe work grows in step with the array: twice the values, twice the looks at worst. A value that is there is found, on average, about halfway through. That's fine for most programs, but one that searches a million values over and over has a lot to do. The next step shows how sorted data makes searching much faster.\n\nThe list methods `indexOf` and `contains` (module 14) do a linear search for you: they go through the list from the start, and compare each element with the value using `equals`.\n\n### Searching a list of objects\n\nOften the values are objects, and the search compares one of their instance variables. Here a music library finds an album by its title:\n\n```java\nimport java.util.ArrayList;\n\npublic class Main {\n    public static void main(String[] args) {\n        ArrayList<Album> albums = new ArrayList<>();\n        albums.add(new Album(\"Kind of Blue\", 1959));\n        albums.add(new Album(\"Abbey Road\", 1969));\n        albums.add(new Album(\"Rumours\", 1977));\n\n        int index = indexOfTitle(albums, \"Abbey Road\");\n        System.out.println(index + \": \" + albums.get(index));\n        System.out.println(indexOfTitle(albums, \"Thriller\"));\n    }\n\n    public static int indexOfTitle(ArrayList<Album> albums, String title) {\n        for (int i = 0; i < albums.size(); i++) {\n            if (albums.get(i).getTitle().equals(title)) {\n                return i;\n            }\n        }\n        return -1;\n    }\n}\n// ==== Album.java ====\npublic class Album {\n    private String title;\n    private int year;\n\n    public Album(String title, int year) {\n        this.title = title;\n        this.year = year;\n    }\n\n    public String getTitle() {\n        return this.title;\n    }\n\n    public int getYear() {\n        return this.year;\n    }\n\n    public String toString() {\n        return this.title + \" (\" + this.year + \")\";\n    }\n}\n```\n\n```output\n1: Abbey Road (1969)\n-1\n```\n\n- The loop goes over the indexes, so that it has an index to return. `albums.get(i)` is the album at index `i`, and `getTitle()` gives its title.\n- Titles are Strings, so they're compared with `equals`, not `==` (module 16).\n- `albums.indexOf` can't do this search: it would need an Album object equal to the one on the list, and all the program has is a title.\n","task":"In a small harbor, each berth holds one boat, and the array `berths` holds the boats' registration numbers, one per berth. Write the method `berthOf(int[] berths, int boat)`, which returns the index of the berth where the boat is, or -1 if it isn't in the harbor. The check runs:\n\n```java\nint[] berths = {305, 118, 442, 97};\nSystem.out.println(berthOf(berths, 442));\nSystem.out.println(berthOf(berths, 500));\n```\n\nand expects:\n\n```\n2\n-1\n```\n","kind":"code","seed":"public class Main {\n    public static void main(String[] args) {\n        int[] berths = {305, 118, 442, 97};\n        System.out.println(berthOf(berths, 442));\n        System.out.println(berthOf(berths, 500));\n    }\n\n    // Write the method berthOf here.\n}\n","solution":"public class Main {\n    public static void main(String[] args) {\n        int[] berths = {305, 118, 442, 97};\n        System.out.println(berthOf(berths, 442));\n        System.out.println(berthOf(berths, 500));\n    }\n\n    public static int berthOf(int[] berths, int boat) {\n        for (int i = 0; i < berths.length; i++) {\n            if (berths[i] == boat) {\n                return i;\n            }\n        }\n        return -1;\n    }\n}\n","hints":["It's `positionOf` from above with new names: go through the berths in order, and return as soon as you find the boat.","Loop over the indexes, `for (int i = 0; i < berths.length; i++)`, and compare `berths[i]` with `boat`. The -1 comes after the loop, once every berth has been checked."],"tests":[{"name":"Test 1","stdin":"","call":"int[] berths = {305, 118, 442, 97};\nSystem.out.println(berthOf(berths, 442));\nSystem.out.println(berthOf(berths, 500));\n","expect":"2\n-1","hidden":false},{"name":"Test 2","stdin":"","call":"int[] berths = {7, 12, 3};\nSystem.out.println(berthOf(berths, 12));\nSystem.out.println(berthOf(berths, 3));\nSystem.out.println(berthOf(berths, 0));\n","expect":"1\n2\n-1","hidden":true},{"name":"Test 3","stdin":"","call":"int[] empty = new int[0];\nSystem.out.println(berthOf(empty, 4));\nint[] one = {4};\nSystem.out.println(berthOf(one, 4));\nint[] berths = {10, 20, 30};\nSystem.out.println(berthOf(berths, 30) + \" \" + berthOf(berths, 10));\n","expect":"-1\n0\n2 0","hidden":true}],"require":[{"pattern":"\\bpublic\\s+static\\s+int\\s+berthOf\\s*\\(\\s*int\\s*\\[\\s*\\]\\s*\\w+\\s*,\\s*int\\s+\\w+\\s*\\)","message":"Write the method as `public static int berthOf(int[] berths, int boat)`."}],"forbid":[],"more":[{"task":"This search has a common mistake in it. What does the program print?\n","kind":"predict","seed":"public class Main {\n    public static void main(String[] args) {\n        int[] codes = {40, 15, 72, 15};\n        System.out.println(find(codes, 40));\n        System.out.println(find(codes, 72));\n        System.out.println(find(codes, 15));\n    }\n\n    public static int find(int[] codes, int wanted) {\n        for (int i = 0; i < codes.length; i++) {\n            if (codes[i] == wanted) {\n                return i;\n            } else {\n                return -1;\n            }\n        }\n        return -1;\n    }\n}\n","solution":"public class Main {\n    public static void main(String[] args) {\n        int[] codes = {40, 15, 72, 15};\n        System.out.println(find(codes, 40));\n        System.out.println(find(codes, 72));\n        System.out.println(find(codes, 15));\n    }\n\n    public static int find(int[] codes, int wanted) {\n        for (int i = 0; i < codes.length; i++) {\n            if (codes[i] == wanted) {\n                return i;\n            } else {\n                return -1;\n            }\n        }\n        return -1;\n    }\n}\n","hints":["In the first round of the loop, `i` is 0. The `if` compares the first code with the wanted one, and both of its branches end the method with `return`.","So the method only ever looks at `codes[0]`. It returns 0 when the first code matches, and -1 for anything else, even for codes that are in the array."],"tests":[{"name":"Output","stdin":"","expect":"0\n-1\n-1","hidden":false}],"require":[],"forbid":[],"lines":["0","-1","-1"]},{"task":"`Departure.java` is ready: a bus departure has a line, such as `\"14\"`, and a time, such as `\"08:05\"`, with the getters `getLine()` and `getTime()`. The departures are in a list, in time order. In `Main.java`, write the method `firstOnLine(ArrayList<Departure> departures, String line)`, which returns the index of the first departure of the given line, or -1 if no bus of that line leaves. The check runs:\n\n```java\nArrayList<Departure> departures = new ArrayList<>();\ndepartures.add(new Departure(\"14\", \"08:05\"));\ndepartures.add(new Departure(\"3\", \"08:12\"));\ndepartures.add(new Departure(\"22\", \"08:20\"));\ndepartures.add(new Departure(\"3\", \"08:31\"));\nSystem.out.println(firstOnLine(departures, \"3\"));\nSystem.out.println(firstOnLine(departures, \"7\"));\n```\n\nand expects:\n\n```\n1\n-1\n```\n","kind":"code","seed":"// ==== Main.java ====\nimport java.util.ArrayList;\n\npublic class Main {\n    public static void main(String[] args) {\n        ArrayList<Departure> departures = new ArrayList<>();\n        departures.add(new Departure(\"14\", \"08:05\"));\n        departures.add(new Departure(\"3\", \"08:12\"));\n        departures.add(new Departure(\"22\", \"08:20\"));\n        departures.add(new Departure(\"3\", \"08:31\"));\n        System.out.println(firstOnLine(departures, \"3\"));\n        System.out.println(firstOnLine(departures, \"7\"));\n    }\n\n    // Write the method firstOnLine here.\n}\n\n// ==== Departure.java ====\npublic class Departure {\n    private String line;\n    private String time;\n\n    public Departure(String line, String time) {\n        this.line = line;\n        this.time = time;\n    }\n\n    public String getLine() {\n        return this.line;\n    }\n\n    public String getTime() {\n        return this.time;\n    }\n\n    public String toString() {\n        return this.time + \" line \" + this.line;\n    }\n}\n","solution":"// ==== Main.java ====\nimport java.util.ArrayList;\n\npublic class Main {\n    public static void main(String[] args) {\n        ArrayList<Departure> departures = new ArrayList<>();\n        departures.add(new Departure(\"14\", \"08:05\"));\n        departures.add(new Departure(\"3\", \"08:12\"));\n        departures.add(new Departure(\"22\", \"08:20\"));\n        departures.add(new Departure(\"3\", \"08:31\"));\n        System.out.println(firstOnLine(departures, \"3\"));\n        System.out.println(firstOnLine(departures, \"7\"));\n    }\n\n    public static int firstOnLine(ArrayList<Departure> departures, String line) {\n        for (int i = 0; i < departures.size(); i++) {\n            if (departures.get(i).getLine().equals(line)) {\n                return i;\n            }\n        }\n        return -1;\n    }\n}\n\n// ==== Departure.java ====\npublic class Departure {\n    private String line;\n    private String time;\n\n    public Departure(String line, String time) {\n        this.line = line;\n        this.time = time;\n    }\n\n    public String getLine() {\n        return this.line;\n    }\n\n    public String getTime() {\n        return this.time;\n    }\n\n    public String toString() {\n        return this.time + \" line \" + this.line;\n    }\n}\n","hints":["Loop over the indexes, `for (int i = 0; i < departures.size(); i++)`, so that you have an index to return. `departures.get(i).getLine()` is the line of the departure at index `i`.","Lines are Strings, so compare them with `equals`. Return `i` at the first match, and -1 after the loop."],"tests":[{"name":"Test 1","stdin":"","call":"ArrayList<Departure> departures = new ArrayList<>();\ndepartures.add(new Departure(\"14\", \"08:05\"));\ndepartures.add(new Departure(\"3\", \"08:12\"));\ndepartures.add(new Departure(\"22\", \"08:20\"));\ndepartures.add(new Departure(\"3\", \"08:31\"));\nSystem.out.println(firstOnLine(departures, \"3\"));\nSystem.out.println(firstOnLine(departures, \"7\"));\n","expect":"1\n-1","hidden":false},{"name":"Test 2","stdin":"","call":"ArrayList<Departure> departures = new ArrayList<>();\ndepartures.add(new Departure(\"22\", \"10:00\"));\ndepartures.add(new Departure(\"5\", \"10:04\"));\ndepartures.add(new Departure(\"22\", \"10:15\"));\nString two = \"2\";\nint index = firstOnLine(departures, two + two);\nSystem.out.println(index + \" \" + departures.get(index));\nSystem.out.println(firstOnLine(departures, \"5\"));\nSystem.out.println(firstOnLine(departures, \"2\"));\n","expect":"0 10:00 line 22\n1\n-1","hidden":true},{"name":"Test 3","stdin":"","call":"ArrayList<Departure> none = new ArrayList<>();\nSystem.out.println(firstOnLine(none, \"1\"));\nnone.add(new Departure(\"1\", \"23:50\"));\nSystem.out.println(firstOnLine(none, \"1\"));\n","expect":"-1\n0","hidden":true}],"require":[{"pattern":"\\bpublic\\s+static\\s+int\\s+firstOnLine\\s*\\(\\s*ArrayList<Departure>\\s+\\w+\\s*,\\s*String\\s+\\w+\\s*\\)","message":"Write the method as `public static int firstOnLine(ArrayList<Departure> departures, String line)`."},{"pattern":"\\.equals\\s*\\(","message":"Compare the lines, which are Strings, with `equals`."}],"forbid":[]}]}