{"id":"sorting-searching-selection-sort","slug":"selection-sort","title":"Selection sort in code","text":"Step 2 wrote the rounds of selection sort out by hand, one line per round. A loop does the same for an array of any length: the round's index goes up from 0, and each round finds the smallest value from that index on, and swaps it there.\n\n```java\nimport java.util.Arrays;\n\npublic class Main {\n    public static void main(String[] args) {\n        int[] heights = {152, 140, 171, 131, 160};\n        selectionSort(heights);\n        System.out.println(Arrays.toString(heights));\n    }\n\n    public static void selectionSort(int[] values) {\n        for (int i = 0; i < values.length - 1; i++) {\n            int lowest = positionOfLowest(values, i);\n            switchPlaces(values, i, lowest);\n        }\n    }\n\n    public static int positionOfLowest(int[] values, int start) {\n        int lowest = start;\n        for (int i = start + 1; i < values.length; i++) {\n            if (values[i] < values[lowest]) {\n                lowest = i;\n            }\n        }\n        return lowest;\n    }\n\n    public static void switchPlaces(int[] values, int a, int b) {\n        int temp = values[a];\n        values[a] = values[b];\n        values[b] = temp;\n    }\n}\n```\n\n```output\n[131, 140, 152, 160, 171]\n```\n\n- The loop variable `i` is the index that the round fills. Everything before it is already sorted, and holds the smallest values of the array.\n- The loop stops before `values.length - 1`, so five values take four rounds: the last value is in place once all the others are.\n- `selectionSort` returns nothing. It sorts the array it's given, in place, and `main` sees the change because both refer to the same array.\n- Short methods with one job each keep the algorithm easy to read: `selectionSort` reads almost like the description in step 2.\n\n### All in one method\n\nSelection sort is often written as one method, with the search for the smallest value as a loop inside the loop of the rounds. The inner loop needs a variable of its own, usually `j`:\n\n```java\npublic static void selectionSort(int[] values) {\n    for (int i = 0; i < values.length - 1; i++) {\n        int lowest = i;\n        for (int j = i + 1; j < values.length; j++) {\n            if (values[j] < values[lowest]) {\n                lowest = j;\n            }\n        }\n        int temp = values[i];\n        values[i] = values[lowest];\n        values[lowest] = temp;\n    }\n}\n```\n\nIt does the same work, line by line: the inner loop is `positionOfLowest` with `i` as its start, and the last three lines are the swap.\n\n### How much work is it?\n\nCount the comparisons `values[j] < values[lowest]`. With 5 values, the first round compares each of the other 4 values with the smallest so far, the next round makes 3 comparisons, then 2, then 1: 10 in all. With `n` values, it's `(n - 1) + (n - 2) + ... + 1` comparisons, which adds up to `n * (n - 1) / 2`:\n\n| Values | Comparisons |\n| --- | --- |\n| 5 | 10 |\n| 1,000 | 499,500 |\n| 2,000 | 1,999,000 |\n| 1,000,000 | 499,999,500,000 |\n\nTwice as many values take about four times as many comparisons. And the order the values start in doesn't help: even an array that's already sorted gets every comparison. Selection sort is fine for a few thousand values, but slow for millions. Much faster sorting algorithms exist, and Java has them ready for you (next step).\n","task":"A depot weighs its parcels, in kilograms. Fill in the blanks of `sortWeights`, so that it sorts the array from the lightest parcel to the heaviest with selection sort. `positionOfLowest` and `switchPlaces` are the methods from above. The check runs:\n\n```java\nint[] weights = {12, 4, 9, 1, 7};\nsortWeights(weights);\nSystem.out.println(Arrays.toString(weights));\n```\n\nand expects:\n\n```\n[1, 4, 7, 9, 12]\n```\n","kind":"fill","seed":"import java.util.Arrays;\n\npublic class Main {\n    public static void main(String[] args) {\n        int[] weights = {12, 4, 9, 1, 7};\n        sortWeights(weights);\n        System.out.println(Arrays.toString(weights));\n    }\n\n    public static void sortWeights(int[] weights) {\n        for (int i = 0; i < [[weights.length - 1‖weights.length]]; i++) {\n            int lightest = positionOfLowest(weights, [[i]]);\n            switchPlaces(weights, i, [[lightest]]);\n        }\n    }\n\n    public static int positionOfLowest(int[] values, int start) {\n        int lowest = start;\n        for (int i = start + 1; i < values.length; i++) {\n            if (values[i] < values[lowest]) {\n                lowest = i;\n            }\n        }\n        return lowest;\n    }\n\n    public static void switchPlaces(int[] values, int a, int b) {\n        int temp = values[a];\n        values[a] = values[b];\n        values[b] = temp;\n    }\n}\n","solution":"import java.util.Arrays;\n\npublic class Main {\n    public static void main(String[] args) {\n        int[] weights = {12, 4, 9, 1, 7};\n        sortWeights(weights);\n        System.out.println(Arrays.toString(weights));\n    }\n\n    public static void sortWeights(int[] weights) {\n        for (int i = 0; i < weights.length - 1; i++) {\n            int lightest = positionOfLowest(weights, i);\n            switchPlaces(weights, i, lightest);\n        }\n    }\n\n    public static int positionOfLowest(int[] values, int start) {\n        int lowest = start;\n        for (int i = start + 1; i < values.length; i++) {\n            if (values[i] < values[lowest]) {\n                lowest = i;\n            }\n        }\n        return lowest;\n    }\n\n    public static void switchPlaces(int[] values, int a, int b) {\n        int temp = values[a];\n        values[a] = values[b];\n        values[b] = temp;\n    }\n}\n","hints":["There's a round for every index but the last, and each round looks for the lightest parcel from the round's own index on.","`positionOfLowest(weights, i)` gives the index of the lightest parcel from index `i` on, and the swap moves that parcel to index `i`: `switchPlaces(weights, i, lightest)`."],"tests":[{"name":"Test 1","stdin":"","call":"int[] weights = {12, 4, 9, 1, 7};\nsortWeights(weights);\nSystem.out.println(Arrays.toString(weights));\n","expect":"[1, 4, 7, 9, 12]","hidden":false},{"name":"Test 2","stdin":"","call":"int[] weights = {5, 5, 3, 8, 3, 1};\nsortWeights(weights);\nSystem.out.println(Arrays.toString(weights));\nint[] reversed = {9, 7, 5, 3, 1};\nsortWeights(reversed);\nSystem.out.println(Arrays.toString(reversed));\n","expect":"[1, 3, 3, 5, 5, 8]\n[1, 3, 5, 7, 9]","hidden":true},{"name":"Test 3","stdin":"","call":"int[] two = {20, 2};\nsortWeights(two);\nSystem.out.println(Arrays.toString(two));\nint[] sorted = {1, 2, 3, 4};\nsortWeights(sorted);\nSystem.out.println(Arrays.toString(sorted));\n","expect":"[2, 20]\n[1, 2, 3, 4]","hidden":true}],"require":[],"forbid":[],"more":[{"task":"Here is the one-method version, with a print at the end of each round. What does it print?\n","kind":"predict","seed":"import java.util.Arrays;\n\npublic class Main {\n    public static void main(String[] args) {\n        int[] numbers = {5, 1, 4, 2};\n        for (int i = 0; i < numbers.length - 1; i++) {\n            int lowest = i;\n            for (int j = i + 1; j < numbers.length; j++) {\n                if (numbers[j] < numbers[lowest]) {\n                    lowest = j;\n                }\n            }\n            int temp = numbers[i];\n            numbers[i] = numbers[lowest];\n            numbers[lowest] = temp;\n            System.out.println(Arrays.toString(numbers));\n        }\n    }\n}\n","solution":"import java.util.Arrays;\n\npublic class Main {\n    public static void main(String[] args) {\n        int[] numbers = {5, 1, 4, 2};\n        for (int i = 0; i < numbers.length - 1; i++) {\n            int lowest = i;\n            for (int j = i + 1; j < numbers.length; j++) {\n                if (numbers[j] < numbers[lowest]) {\n                    lowest = j;\n                }\n            }\n            int temp = numbers[i];\n            numbers[i] = numbers[lowest];\n            numbers[lowest] = temp;\n            System.out.println(Arrays.toString(numbers));\n        }\n    }\n}\n","hints":["The first round finds the smallest value, 1, at index 1, and swaps it with the 5 at index 0. The inner loop of the next round starts from index 2, and so on.","The array can be sorted before the last round, but the loop doesn't check for that. There are always `numbers.length - 1` rounds, and each one prints."],"tests":[{"name":"Output","stdin":"","expect":"[1, 5, 4, 2]\n[1, 2, 4, 5]\n[1, 2, 4, 5]","hidden":false}],"require":[],"forbid":[],"lines":["[1, 5, 4, 2]","[1, 2, 4, 5]","[1, 2, 4, 5]"]},{"task":"The board-game club from step 1 wants its scores from the highest down. Write the method `sortHighFirst(int[] scores)`, which sorts the array it's given from the highest score to the lowest with selection sort: each round finds the highest score from the round's index on, and swaps it there. Write it as one method or with helper methods, as you like (step 1's `highestFrom` would fit right in). The check runs:\n\n```java\nint[] scores = {42, 57, 38, 57, 49};\nsortHighFirst(scores);\nSystem.out.println(Arrays.toString(scores));\n```\n\nand expects:\n\n```\n[57, 57, 49, 42, 38]\n```\n","kind":"code","seed":"import java.util.Arrays;\n\npublic class Main {\n    public static void main(String[] args) {\n        int[] scores = {42, 57, 38, 57, 49};\n        sortHighFirst(scores);\n        System.out.println(Arrays.toString(scores));\n    }\n\n    // Write the method sortHighFirst here.\n}\n","solution":"import java.util.Arrays;\n\npublic class Main {\n    public static void main(String[] args) {\n        int[] scores = {42, 57, 38, 57, 49};\n        sortHighFirst(scores);\n        System.out.println(Arrays.toString(scores));\n    }\n\n    public static void sortHighFirst(int[] scores) {\n        for (int i = 0; i < scores.length - 1; i++) {\n            int highest = i;\n            for (int j = i + 1; j < scores.length; j++) {\n                if (scores[j] > scores[highest]) {\n                    highest = j;\n                }\n            }\n            int temp = scores[i];\n            scores[i] = scores[highest];\n            scores[highest] = temp;\n        }\n    }\n}\n","hints":["It's the selection sort of this step with one change: each round looks for the *highest* score from index `i` on, so the comparison is `scores[j] > scores[highest]`.","After the inner loop, swap the scores at `i` and at `highest`, with a `temp` variable. The outer loop runs `for (int i = 0; i < scores.length - 1; i++)`."],"tests":[{"name":"Test 1","stdin":"","call":"int[] scores = {42, 57, 38, 57, 49};\nsortHighFirst(scores);\nSystem.out.println(Arrays.toString(scores));\n","expect":"[57, 57, 49, 42, 38]","hidden":false},{"name":"Test 2","stdin":"","call":"int[] scores = {-3, 0, -7, 5};\nsortHighFirst(scores);\nSystem.out.println(Arrays.toString(scores));\nint[] rising = {1, 2, 3, 4, 5, 6};\nsortHighFirst(rising);\nSystem.out.println(Arrays.toString(rising));\n","expect":"[5, 0, -3, -7]\n[6, 5, 4, 3, 2, 1]","hidden":true},{"name":"Test 3","stdin":"","call":"int[] one = {9};\nsortHighFirst(one);\nSystem.out.println(Arrays.toString(one));\nint[] none = new int[0];\nsortHighFirst(none);\nSystem.out.println(Arrays.toString(none));\nint[] same = {4, 8, 4, 8, 4};\nsortHighFirst(same);\nSystem.out.println(Arrays.toString(same));\n","expect":"[9]\n[]\n[8, 8, 4, 4, 4]","hidden":true}],"require":[{"pattern":"\\bpublic\\s+static\\s+void\\s+sortHighFirst\\s*\\(\\s*int\\s*\\[\\s*\\]\\s*\\w+\\s*\\)","message":"Write the method as `public static void sortHighFirst(int[] scores)`."}],"forbid":[{"pattern":"\\bArrays\\s*\\.\\s*sort\\b|\\bCollections\\b","message":"Sort the scores with your own selection sort, not with Java's ready-made sorting."}]}]}