23SortingRecursion and sorting

Selection sort

A row to put in order: find the smallest number in the unsorted part, swap it into the next spot, and repeat.

Put a row of numbers in order by finding the smallest one and moving it to the front. Worked example: the row 5 2 4 1 3.

The idea

Look at the whole row, find the smallest card, and swap it into the first spot. That spot is now final, so it joins the sorted part. Then do the same for the second spot, using only the cards that are left. Each pass fixes one spot, so the sorted part grows by one every time.

The part that trips people up is what to remember while scanning. Remember the spot of the smallest card, not its value. With the spot you can swap; with only the value you cannot tell where it came from.

The walk

Selection sort on 5 2 4 1 3 needs 4 passes. The last number is already in place after the fourth pass, so a fifth pass would do nothing.

PassSmallest foundSwapRow after
11 at spot 3spots 0 and 31 2 4 5 3
22 at spot 1none, already in place1 2 4 5 3
33 at spot 4spots 2 and 41 2 3 5 4
44 at spot 4spots 3 and 41 2 3 4 5

Quick check: selection sort on 3 1 2. After pass 1 the smallest, 1, is at spot 1. Swapping it with spot 0 gives 1 3 2.

Pseudocode

Pseudocode · any language
function selectionSort(row):
    for i from 0 to length(row) - 2:
        smallest = i   // remember the spot
        for j from i + 1 to length(row) - 1:
            if row[j] < row[smallest]:
                smallest = j
        swap row[i], row[smallest]
    return row

The trap: keeping the smallest value instead of its spot. Writing smallest = row[j] and then row[i] = smallest on 5 2 4 1 3 gives 1 2 4 1 3: the 5 is overwritten and there are two 1s. Keeping the spot and swapping gives 1 2 4 5 3, and nothing is lost.

Code

class Solution {
    public int[] selectionSort(int[] row) {
        for (int i = 0; i < row.length - 1; i++) {
            int smallest = i;
            for (int j = i + 1; j < row.length; j++) {
                if (row[j] < row[smallest]) {
                    smallest = j;
                }
            }
            int temp = row[i];
            row[i] = row[smallest];
            row[smallest] = temp;
        }
        return row;
    }
}

Complexity

  • Time: about n × n steps in every case, because the inner loop always scans the whole unsorted part. For 5 numbers that is 4 + 3 + 2 + 1 = 10 comparisons, even if the row is already sorted.
  • Extra space: O(1), just a few variables. It makes at most one swap per pass, so 3 swaps on 5 2 4 1 3.

How it was tested

All four versions were run on 1,507 inputs each: 7 fixed cases (empty, single number, all equal, already sorted, reversed, and the two worked rows) plus 1,500 random rows of up to 12 numbers between -20 and 20. Every result matched the built-in sort. The code on this page was then run again from the finished solutions file, with 0 mismatches.

Practice

Try these in order. Open the worked example first if you got stuck on the slides.