Binary search algorithm & trace

Binary search efficiently searches an array to find a given key. The array must already be sorted for the algorithm to work.

For the example traces below, the algorithm returns the position of key in arr or -1 if key is not in arr. A more sophisticated return value when key is not found is featured below in the Binary search with insertion point return section.

Example 1

Step 1

arr -> [11 24 35 36 71 75 78 79 86 86]
        0  1  2  3  4  5  6  7  8  9

key: 35

low: 0
high: 9

arr and key are parameters. low and high (sometimes called start and end) are indexes that represent the bounds of the part of the array that remains to be searched. The initial values of low and high are 0 and arr.length - 1, respectively.

Step 2

The value of mid is the average of low and high, calculated using integer division (drop any decimal portion).

mid: 4

key (35) is less than arr[mid] (71). If key is in arr, it must be to the left of mid. The value of high is updated to mid - 1. The value of low remains the same.

arr -> [11 24 35 36 71 75 78 79 86 86]
        0  1  2  3  4  5  6  7  8  9

key: 35

low: 0
high: 3

Step 4

mid: 1

key (35) is greater than arr[mid] (24). low is updated to mid + 1.

arr -> [11 24 35 36 71 75 78 79 86 86]
        0  1  2  3  4  5  6  7  8  9

key: 35

low: 2
high: 3

Step 5

mid: 2

key (35) is equal to arr[mid]. The algorithm stops and returns mid (2), which is the position of key in arr.

Example 2

arr -> [11 24 35 36 71 75 78 79 86 86]
        0  1  2  3  4  5  6  7  8  9

key: 86
low high mid
0 9 4
5 9 7
8 9 8

The algorithm returns 8, a position of 86 in arr.

In this example, the algorithm happened to find the first 86 in the array. This is not always the case. If asked what is returned when executing binary search on an array with more than 1 copy of key, trace the algorithm to find the specific index returned.

Example 3

arr -> [11 24 35 36 71 75 78 79 86 86]
        0  1  2  3  4  5  6  7  8  9

key: 40
low high mid
0 9 4
0 3 1
2 3 2
3 3 3
4 3 not computed

On the last step, low is greater than high. This means there are 0 elements in the part of the array left to search, so key is not in arr.

On the step above, low == high. We cannot stop just because low == high. There is still 1 element to check.

Binary search implementations

private static int binarySearch(int[] arr, int key, int low, int high)
{
	if (low > high)
		return -1;
	
    int mid = (low + high) / 2;

    if (key < arr[mid])
        return binarySearch(arr, key, low, mid - 1);
    else if (key > arr[mid])
        return binarySearch(arr, key, mid + 1, high);
    else
        return mid;
}

public static int binarySearch(int[] arr, int key)
{
	return binarySearch(arr, key, 0, arr.length - 1);
}

Binary search is easy to implement recursively. The private method takes the parameters necessary to constrain the search to part of the array. The public method takes the parameters appropriate for a search method.

As mentioned above, the precondition for binary search is that the array is sorted.

public static int binarySearch(int[] arr, int key)
{
    int low = 0;
    int high = arr.length - 1;
    
    while(low <= high)
    {
        int mid = (low + high) / 2;

        if (key < arr[mid])
            high = mid - 1;
        else if (key > arr[mid])
            low = mid + 1;
        else
            return mid;
    }
    
    return -1;
}

The iterative implementation of binary search creates low and high as local variables instead of as parameters.

Binary search with insertion point return

public static int binarySearch(int[] arr, int key, int low, int high)
{
	if (low > high)
		return -low - 1;
	
    int mid = (low + high) / 2;
    int result = key - arr[mid];

    if (result < 0)
        return binarySearch(arr, key, low, mid - 1);
    else if (result > 0)
        return binarySearch(arr, key, mid + 1, high);
    else
        return mid;
}

The version of binary search above is identical to the original except that it returns a more sophisticated value when key is not found in arr. A simple version of binary search returns -1 when key is not found in arr. Since arr is sorted, there is additional information available when key is not found. Specifically, the algorithm knows the position at which key would need to be inserted into arr to maintain the sorted order. This position is known as the insertion point.

If low > high (the base case) the insertion point is low. The method above returns -low - 1. This allows for quick examination of the return value to determine if key was found. (A negative return value indicates that key was not found.) It also allows for quick convertion to the actual insertion point if desired.

Problem #10 in the 2014 AP CS A Course Description sample multiple choice makes use of a variant of the above. The variant in the problem returns the actual insertion point (low) rather than a modified version of it (-low - 1).

One of my insertion sort variants calls the method above to determine where to insert the element into the sorted part.

Binary search with ArrayList<String>

public static int binarySearch(ArrayList<String> list, String key, int start, int end)
{
    if (start > end)
        return -start - 1;
    else
    {
        int mid = (start + end) / 2;
        int result = key.compareTo(list.get(mid));

        if (result < 0)
            return binarySearch(list, key, start, mid - 1);
        else if (result > 0)
            return binarySearch(list, key, mid + 1, end);
        else
            return mid;
    }
}

This is nearly identical to the variant above, except it uses compareTo. The result of the call to compareTo is stored in result to avoid calling compareTo twice.

For more about how to handle compareTo on the AP CS A Exam, see compareTo on the AP CS A Exam.

AP CS A Exam sort & search algorithms

Comments

Comment on Binary search