Skip to content
Study Hall
Lesson 3 of 5Arrays
Unit 6 · Lesson 3 of 5

Sorting and Binary Search

Two classic sorts traced pass by pass, why a method can sort the caller's array, and how sorted data lets binary search find anything in a handful of steps.

8 min read11 practice questionsInteractiveAsk AI about this →

Key things to remember

  1. 1Selection sort: each pass finds the smallest unsorted value and swaps it into the next slot; n elements need n − 1 passes and n(n − 1)/2 comparisons.
  2. 2Bubble sort: each pass swaps out-of-order neighbours, carrying the largest remaining value to the end; a pass with no swaps means the array is sorted.
  3. 3Swapping two elements always needs a temporary variable: save, copy over, restore.
  4. 4Java passes arguments by value, but an array variable's value is a reference, so a method can change the caller's elements — not which array the caller's variable points to.
  5. 5Binary search requires sorted data; it checks the middle, then discards half the range, using low = mid + 1 or high = mid - 1.
  6. 6Worst-case binary search on n elements needs floor(log₂ n) + 1 checks — 20 for a million elements, against a million for linear search.

Think about finding a word in a paper dictionary. You never start at page one and read every entry; you open somewhere near the middle, see that you have gone too far, and flip back. That trick only works because the words are in alphabetical order. A linear search through an unsorted array has no such shortcut — it must look at every element, and for a million records that is a million checks. Sorting the data first changes what is possible: once it is in order, each check can rule out half of what is left. This lesson builds the two pieces separately. First, two simple sorting algorithms you can trace by hand; then binary search, the algorithm that cashes in on the order.

Selection sort: find the smallest, put it in place

Selection sort splits the array into a sorted part on the left, which starts empty, and an unsorted part on the right. Each pass scans the unsorted part for its smallest value and swaps it into the first unsorted slot, so the sorted part grows by one element per pass. After pass 1 the smallest value is at index 0 and never moves again; after pass 2 the second smallest is at index 1, and so on. With n elements you need n − 1 passes, because once all but one element are in place the last one has nowhere else to go. Notice that the swap is the same three-line save, copy over, restore you already know.

public static void selectionSort(int[] arr) {
    for (int i = 0; i < arr.length - 1; i++) {
        int minIndex = i;                       // assume the first unsorted slot is smallest
        for (int j = i + 1; j < arr.length; j++) {
            if (arr[j] < arr[minIndex]) {
                minIndex = j;                   // remember WHERE the smaller value is
            }
        }
        int temp = arr[i];                      // swap it into position i
        arr[i] = arr[minIndex];
        arr[minIndex] = temp;
    }
}
The inner loop only finds the position of the minimum. The single swap happens after it finishes.
After passSmallest foundSwapArray
start——{29, 10, 14, 37, 13, 5}
15 at index 5index 0 and 5{5, 10, 14, 37, 13, 29}
210 at index 1index 1 with itself{5, 10, 14, 37, 13, 29}
313 at index 4index 2 and 4{5, 10, 13, 37, 14, 29}
414 at index 4index 3 and 4{5, 10, 13, 14, 37, 29}
529 at index 5index 4 and 5{5, 10, 13, 14, 29, 37}
Six elements, five passes. The sorted part on the left grows by exactly one element each pass.
Selection sort: each pass swaps the smallest unsorted value into placeindex012345start29101437135unsortedafter pass 151014371329min 5 at index 5 · swap 0 ↔ 5after pass 251014371329min 10 at index 1 · swaps with itselfafter pass 351013371429min 13 at index 4 · swap 2 ↔ 4after pass 451013143729min 14 at index 4 · swap 3 ↔ 4after pass 551013142937min 29 at index 5 · swap 4 ↔ 5sorted part (final)the two swapped elements6 elements → 5 passes, 15 comparisons
Fig 1Selection sort on a six-element array, one row per pass, with the two swapped elements marked.

Bubble sort: neighbours swap until nothing moves

Bubble sort works only with neighbours. Each pass walks along the array comparing arr[j] with arr[j + 1] and swaps them whenever they are out of order. The largest value gets carried along like a bubble rising and lands in the last slot at the end of pass 1, so each later pass can stop one element earlier — that is what the - pass in the inner loop bound does. Bubble sort has one genuine advantage: if a whole pass makes no swaps, every neighbour pair is already in order, so the array is sorted and the method can stop early. On nearly sorted data that early exit can save almost all of the work. Selection sort has no such test; it always performs every pass, even on an array that was sorted to begin with.

public static void bubbleSort(int[] arr) {
    for (int pass = 0; pass < arr.length - 1; pass++) {
        boolean swapped = false;
        for (int j = 0; j < arr.length - 1 - pass; j++) {
            if (arr[j] > arr[j + 1]) {
                int temp = arr[j];
                arr[j] = arr[j + 1];
                arr[j + 1] = temp;
                swapped = true;
            }
        }
        if (!swapped) {
            break;               // a pass with no swaps means it is sorted
        }
    }
}
Starting from {29, 10, 14, 37, 13, 5}, pass 1 gives {10, 14, 29, 13, 5, 37}: 37 has bubbled to the end.

Why sorting inside a method changes the caller's array

Both sort methods return void, yet after selectionSort(scores); the caller's scores array is sorted. That seems to contradict what you learned about parameters, so look closely. Java always passes arguments by value: the method receives a copy of whatever the variable holds. For an int the variable holds the number itself, so the method gets its own copy of the number and changing it does nothing outside. An array variable, however, does not hold the elements. It holds a reference — the address of the one array object in memory. Copying the reference gives the method a second arrow pointing at the same array, so arr[0] = 5 inside the method writes into the caller's array. What the method cannot do is make the caller's variable point at a different array: assigning arr = new int[3] just swings the method's own copy of the arrow.

public static void resetToZero(int n) {
    n = 0;                       // changes the method's own copy
}

public static void replace(int[] arr) {
    arr = new int[] {0, 0, 0};   // points the local copy somewhere new
}

public static void main(String[] args) {
    int count = 6;
    int[] scores = {29, 10, 14, 37, 13, 5};

    resetToZero(count);
    selectionSort(scores);       // writes through the shared reference
    replace(scores);

    System.out.println(count);       // 6
    System.out.println(scores[0]);   // 5
}
count is untouched, the elements of scores were sorted, and replace had no effect on the caller at all.

Binary search: halve what is left every step

Binary search keeps two markers, low and high, around the part of a sorted array that could still contain the target. It checks the middle element. If that is the target, it is done. If the middle value is too small, the target can only be to the right, so low moves to mid + 1; if it is too large, high moves to mid - 1. Either way, half of the remaining elements are discarded with one comparison. When low passes high the range is empty and the target is not there, so the method returns −1. Because mid = (low + high) / 2 uses integer division, the middle of an even-sized range rounds down. The halving is what makes it so fast. The worst case is the number of halvings needed to shrink the range to one element, plus one last check: floor(log₂ n) + 1. That is 4 checks for 10 elements, 7 for 100, 10 for 1,000 and only 20 for 1,000,000, where a linear search could need all million — and doubling the data adds just one more check. One warning before you use it: the whole method rests on the assumption that everything left of mid is smaller and everything right of mid is larger. On an unsorted array that is false, so binary search can discard the half that holds the target and confidently return −1 for a value that is present — and Java will not warn you. Sort first or search linearly, and remember that sorting costs time too, so it pays off when you search the same data many times.

public static int binarySearch(int[] data, int target) {
    int low = 0;
    int high = data.length - 1;
    while (low <= high) {
        int mid = (low + high) / 2;
        if (data[mid] == target) {
            return mid;
        } else if (data[mid] < target) {
            low = mid + 1;           // target is in the right half
        } else {
            high = mid - 1;          // target is in the left half
        }
    }
    return -1;                       // range is empty: not found
}
Searching {3, 8, 12, 17, 21, 26, 30, 34, 41, 45, 52, 58, 63, 70, 77} for 58 checks index 7 (34), then index 11 (58) — found in two checks.
binarySearch(data, 63): each check throws away half of what is leftindex01234567891011121314check 13812172126303441455258637077lowmidhighmid = (0 + 14) / 2 = 7data[7] = 34 < 63 → low = mid + 1 = 815 leftcheck 23812172126303441455258637077lowmidhighmid = (8 + 14) / 2 = 11data[11] = 58 < 63 → low = mid + 1 = 127 leftcheck 33812172126303441455258637077lowmidhighmid = (12 + 14) / 2 = 13data[13] = 70 > 63 → high = mid − 1 = 123 leftcheck 43812172126303441455258637077low = mid = highmid = (12 + 12) / 2 = 12data[12] = 63 = 63 → found, return 121 leftRange size 15 → 7 → 3 → 1: at most floor(log₂ 15) + 1 = 4 checks for 15 elements.Greyed, dashed cells have been ruled out; the bracket marks low to high, the range still in play.
Fig 2low, mid and high on a sorted array. Each comparison throws away the half that cannot hold the target.

Try it yourself

Loading interactive…

Worked examples

Reveal one step at a time and try to beat it to the next line.

Example 1
Trace selection sort on {8, 3, 6, 1}, showing the array after each pass.
Example 2
Trace the bubble sort method with the early exit on {5, 1, 4, 2, 8}. How many passes run?
Example 3
Use the binarySearch method to search {3, 8, 12, 17, 21, 26, 30, 34, 41, 45, 52, 58, 63, 70, 77} for 40. Show low, high and mid on every pass and state the result.
Example 4
A library catalogue holds 50,000 book IDs. The program will run 1,000 lookups. Compare the worst-case number of checks for linear search and for binary search, and comment on the cost of sorting.

Where marks get lost

  • Swapping inside selection sort's inner loop every time a smaller value is found, instead of remembering minIndex and swapping once after the scan.
  • Writing the inner bubble-sort loop as j < arr.length, so arr[j + 1] runs one past the end and throws ArrayIndexOutOfBoundsException.
  • Running binary search on an unsorted array and trusting the −1 it returns.
  • Writing low = mid or high = mid instead of mid + 1 and mid - 1, which can loop forever once low and high are next to each other.
  • Expecting a method that assigns arr = new int[...] to replace the caller's array — it only redirects the method's own copy of the reference.

Flashcards 9

Selection sort in one sentence
Bubble sort in one sentence
How many passes does selection sort make on n elements?
What lets bubble sort stop early?
+ 5 more

Practice

1
Selection sort is applied to {29, 10, 14, 37, 13, 5}. What is the array after the FIRST pass?
2
How many comparisons arr[j] < arr[minIndex] does selection sort make on an array of 6 elements?
comparisons
3
Bubble sort (largest values bubble to the end) is applied to {4, 9, 2, 7}. After pass 1, which statement is guaranteed?
4
int[] d = {3, 8, 12, 17, 21, 26, 30, 34, 41, 45, 52, 58, 63, 70, 77}; What does binarySearch(d, 58) return?
5
What is the maximum number of checks binary search needs on a sorted array of 1,000 elements?
checks
6
binarySearch(d, 21) runs on {3, 8, 12, 17, 21, 26, 30, 34, 41, 45, 52, 58, 63, 70, 77}. Put the elements it checks in the order it checks them.
  1. 1d[3] = 17
  2. 2d[4] = 21
  3. 3d[5] = 26
  4. 4d[7] = 34
7
In one word, what must be true of an array before binary search can be used on it?
8
static void change(int n, int[] a) { n = 99; a[0] = 99; } is called as change(x, arr); where x is 1 and arr is {1, 2}. What are x and arr[0] afterwards?
9
Match each algorithm to its defining action.
Selection sort
Bubble sort
Linear search
Binary search
10
Why does selection sort NOT benefit from an already sorted input, while bubble sort with a swapped flag does?
11
Binary search is run on {3, 8, 12, 17, 21, 26, 30, 34, 41, 45, 52, 58, 63, 70, 77} for the target 40. How many times does the body of the while loop run?
passes

Spot a mistake on this page? Let us know