Selection sort
On This Lesson 11 topics
Lesson Overview
Bubble sort moves values by swapping neighbours again and again. Selection sort takes a different path. Imagine lining up books on a shelf by height: you scan all the books on the table, pick the shortest, and put it first on the shelf. Then you scan what is left, pick the shortest again, and put it second. The shelf grows in order, one book at a time.
In code, the array is split in two: a sorted part at the left that grows, and an unsorted part at the right that shrinks. Each pass finds the smallest value in the unsorted part and swaps it into the next position of the sorted part.
Why this matters: selection sort gives you a second algorithm for the same problem, so you can compare them. It also does very few swaps, which makes it a good example of "different algorithms have different costs", and it is a regular junior interview question next to bubble sort.
This lesson builds on bubble sort, nested loops, swapping, and tracing arrays by hand.
Learning Objectives
By the end of this lesson you will be able to:
- Describe selection sort as "repeatedly select the smallest remaining value".
- Implement selection sort for an
int[]. - Explain the role of the
minindex and why we remember an index, not a value. - Trace selection sort on a small array, showing the array after each pass.
- State how many swaps it makes (at most
n - 1) and how many comparisons (aboutn × n / 2). - Compare selection sort with bubble sort.
- Handle the empty and one-element arrays.
Written Explanation
The idea
For {29, 10, 14, 37, 13}:
- The whole array is unsorted. The smallest value is 10 (at index 1). Swap it with the value at index 0. Now
{10, 29, 14, 37, 13}, and position 0 is final. - From index 1 on, the smallest is 13 (at index 4). Swap it with index 1. Now
{10, 13, 14, 37, 29}. - From index 2 on, the smallest is 14 (already at index 2). It stays.
- From index 3 on, the smallest is 29 (at index 4). Swap with index 3. Now
{10, 13, 14, 29, 37}. - One element is left and it must be the largest, so we stop.
Each pass fixes one position for good. A position in the sorted part never changes again.
The code
static void selectionSort(int[] a) {
for (int i = 0; i < a.length - 1; i++) {
int min = i;
for (int j = i + 1; j < a.length; j++) {
if (a[j] < a[min]) min = j;
}
int t = a[i]; a[i] = a[min]; a[min] = t;
}
}How to read it:
iis the first position of the unsorted part. Everything beforeiis sorted and final.minholds the index of the smallest value seen so far. It starts asi(assume the first one is the smallest).- The inner loop checks every later position
j. Ifa[j]is smaller than the current smallest,minbecomesj. - After the inner loop,
minis the index of the smallest value in the unsorted part. One swap puts it at positioni.
Why remember the index and not the value? Because we need to know where to swap from. If we kept only the value, we could not find its position again without another search.
The outer loop stops before the last element (i < a.length - 1). When only one element remains, it is already the largest and already in place.
Tracing it
A version that prints after each pass shows the process on the example:
pass 1: smallest 10 at 1, [10, 29, 14, 37, 13]
pass 2: smallest 13 at 4, [10, 13, 14, 37, 29]
pass 3: smallest 14 at 2, [10, 13, 14, 37, 29]
pass 4: smallest 29 at 4, [10, 13, 14, 29, 37]Pass 3 shows a detail: the smallest was already in the right place (min == i), so the swap exchanged the element with itself and nothing changed. The code swaps anyway. It is simpler, and it costs almost nothing.
Counting the work
Selection sort always scans the whole unsorted part to be sure it found the smallest. So:
- Comparisons:
n - 1, thenn - 2, down to 1, the same total as bubble sort: 10 for 5 elements and 780 for 40. This number does not depend on the data. An already sorted array costs exactly as many comparisons as a reversed one, and there is no early exit. - Swaps: exactly one per pass, so
n - 1at most (some of them swap an element with itself). Bubble sort could make many more swaps on a reversed array: 10 for the reversed 5-element array, against 4 for selection sort.
Both algorithms grow like n × n in comparisons, so for large arrays both are slow. If swapping is expensive (writing to slow storage, for example), selection sort's low swap count can matter. For plain int values it usually does not.
| Bubble sort | Selection sort | |
|---|---|---|
| Idea | Swap out-of-order neighbours | Pick the smallest remaining, place it |
| Comparisons (n = 5) | 10 | 10 |
| Swaps, worst case | up to about n × n / 2 | at most n - 1 |
| Early exit if sorted | Yes, with a flag | No |
Examples
Example 1: the shelf of books (simple)
Heights in centimetres: {29, 10, 14, 37, 13}, the array traced above. The shelf (sorted part) grows like this:
| after pass | shelf (sorted part) | still on the table |
|---|---|---|
| 1 | 10 | 29, 14, 37, 13 |
| 2 | 10, 13 | 14, 37, 29 |
| 3 | 10, 13, 14 | 37, 29 |
| 4 | 10, 13, 14, 29 | 37 |
The last book is the tallest and automatically in the right place.
Example 2: an already sorted array still does the work (practical)
selectionTraced(new int[]{1, 2, 3, 4, 5});Output:
pass 1: smallest 1 at 0, [1, 2, 3, 4, 5]
pass 2: smallest 2 at 1, [1, 2, 3, 4, 5]
pass 3: smallest 3 at 2, [1, 2, 3, 4, 5]
pass 4: smallest 4 at 3, [1, 2, 3, 4, 5]Every pass finds the smallest at the position i, so nothing really moves, but the inner loop still compares all the remaining values. Contrast this with bubble sort with an early exit, which needs a single pass here. The edge cases work without special code: for {} and {5} the outer loop does not run, so the arrays are unchanged ([] [5]).
Example 3: sorting a copy and keeping the original (realistic)
A report needs sorted prices, but another part of the program relies on the original order. Because the sort changes the array in place, we sort a copy:
static int[] sortedCopy(int[] a) {
int[] c = Arrays.copyOf(a, a.length);
selectionSort(c);
return c;
}int[] orig = {8, 3, 6};
int[] c = sortedCopy(orig);
System.out.println(Arrays.toString(orig) + " " + Arrays.toString(c));Output:
[8, 3, 6] [3, 6, 8]Arrays.copyOf was introduced with the arrays utility class. The original is untouched. Repeated values are also fine: {3, 1, 3, 2, 1} becomes [1, 1, 2, 3, 3].
Backend Insight
Choosing between two correct algorithms is a daily backend decision, and the choice depends on what is expensive. Counting is the tool: selection sort and bubble sort both compare about the same number of pairs, but one swaps far less. In a service, "expensive" might be network calls, disk writes, or database queries, and the same thinking applies: reduce the number of expensive operations, not just the number of loops.
Another point is predictability. Selection sort takes the same number of comparisons whatever the input, while an algorithm with an early exit is fast on nearly sorted data. Knowing how an algorithm behaves on already sorted, reversed, and repeated data is what makes it safe to use. In practice you will call the library's Arrays.sort rather than hand-write either of these.
Common Mistakes
Mistake 1: Swapping inside the inner loop
Writing the swap inside for (int j ...) turns selection sort into a messier algorithm that does many swaps and is easy to get wrong. Find the minimum first (remember only the index), then swap once after the inner loop.
Mistake 2: Storing the value instead of the index
If you save int min = a[i] you can find the smallest value but lose its position, so you cannot swap it. Keep the index.
Mistake 3: Starting the inner loop at the wrong place
j = ialso works, because comparing an element with itself is harmless, but wastes a comparison.j = 0is wrong: it would pick a value from the sorted part and undo the work.j = i + 1is the correct start.
Mistake 4: Running the outer loop one time too far
i < a.length instead of i < a.length - 1 adds a pass in which the inner loop does not run and min stays equal to i, so it is harmless but pointless. The more dangerous version is writing j <= a.length, which reads past the end of the array.
Exercises
Try each exercise yourself before opening the solutions.
Level A: Foundation
A1. What does selection sort pick on each pass?
Show solution A1
A1. The smallest value of the unsorted part, which it swaps into the next position.
A2. In the first pass on {6, 2, 5, 1}, what is min at the end of the inner loop, and what is swapped?
Show solution A2
A2. The smallest value is 1 at index 3, so min is 3. The values at index 0 and index 3 are swapped, giving {1, 2, 5, 6}.
A3. How many swaps does selection sort make at most on 8 elements?
Show solution A3
A3. At most 7 (that is n - 1).
Level B: Application
B1. Trace selection sort on {6, 2, 5, 1}: write the array after each pass.
Show solution B1
B1.
after pass 1: [1, 2, 5, 6]
after pass 2: [1, 2, 5, 6]
after pass 3: [1, 2, 5, 6]Pass 1 swaps 6 and 1, which also puts the array in order. Passes 2 and 3 find the smallest already in place (the swaps are self-swaps) and change nothing, but the algorithm does not know that, so it still runs them.
B2. Modify the method so that it sorts in descending order. Which line changes?
Show solution B2
B2. Select the largest instead of the smallest: rename min to max and change the test to if (a[j] > a[max]) max = j;. Run on {2, 9, 4, 7} it gives [9, 7, 4, 2].
B3. What happens when selection sort is called on {}? On {5}? Explain why no special code is needed.
Show solution B3
B3. For {}, a.length - 1 is -1, so the outer loop never starts. For {5}, a.length - 1 is 0, and i < 0 is false at once. Both arrays stay unchanged, which is correct.
Level C: Challenge
C1. Write a method static int swapCount(int[] a) that sorts the array with selection sort and returns the number of swaps it performed. Test it on {5, 4, 3, 2, 1}.
Show solution C1
C1.
static int swapCount(int[] a) {
int swaps = 0;
for (int i = 0; i < a.length - 1; i++) {
int min = i;
for (int j = i + 1; j < a.length; j++) {
if (a[j] < a[min]) min = j;
}
int t = a[i]; a[i] = a[min]; a[min] = t;
swaps++;
}
return swaps;
}On {5, 4, 3, 2, 1} it returns 4, because it swaps once per pass, n - 1 times. If you only count swaps where min != i, you get a smaller number for some inputs; either definition is acceptable if you state it.
C2. Write a short comparison for a teammate: for which kind of input would you choose bubble sort with the early exit, and for which selection sort? Justify with step counts.
Show solution C2
C2. Bubble sort with early exit suits nearly sorted data: an array that is already sorted needs n - 1 comparisons, whereas selection sort always needs about n × n / 2. Selection sort suits cases where a swap is much more expensive than a comparison, because it makes at most n - 1 swaps, while bubble sort on reversed data makes about as many swaps as comparisons (10 for 5 elements). For plain numbers and small arrays the difference rarely matters, and both are replaced by the library sort in real programs.
Mini Challenge
Make a deck of six cards as an int[] (values 1 to 10, with one repeated value, in random order). By hand, write the array after each pass of selection sort, and note which pass made a self-swap. Then add println statements to your method to confirm, and use isSorted to check the final result. Finally, run your method on {} and on a one-element array.
Check your work: your hand trace equals the program output on every pass, and both small arrays run without an exception.
Summary & Next Lesson
Key takeaways
- Selection sort repeatedly selects the smallest remaining value and swaps it into the next position of the sorted part.
- Remember the index of the minimum, find it with the inner loop, then swap once per pass.
- It makes at most
n - 1swaps but still aboutn × n / 2comparisons, and it does the same comparisons whether or not the array is already sorted. - Compared with bubble sort, it swaps much less but has no early exit.
- The empty and one-element arrays need no special code.
Next lesson
The next lesson, "Counting steps: a first look at efficiency", adds counters to the algorithms from this module and uses the numbers to compare how they grow as the data gets bigger.
Self-check
- What does the variable
minstore? - When is the swap done: inside the inner loop or after it?
- How many swaps does selection sort make at most for
nelements? - Does selection sort stop early on a sorted array?
- Where does the inner loop start, and why?
Show answers
- The index of the smallest value found so far in the unsorted part.
- After it, once per pass.
n - 1.- No. It always does all the comparisons.
- At
i + 1, because everything beforeiis the sorted part anda[i]is the starting candidate.
References
- Oracle, Arrays (Java SE 21 API). Documents the library's
sortandcopyOfmethods that real code uses instead of a hand-written sort. - The traces, swap counts, and outputs in this lesson come from compiling and running the code on JDK 21. The claim that selection sort makes at most
n - 1swaps and aboutn × n / 2comparisons follows directly from the loop structure; the table comparing it with bubble sort is this course's own summary.
Practice
Apply this lesson with the module's lab, exercises and quiz.
Marking a lesson complete is optional and you can undo it any time. Your progress stays in this browser.