1.6 Case study: Searching in a list
If you want to find the position in an unsorted array of objects that stores a particular value, you cannot really do better than simply looking through the array from the beginning and moving toward the end until you find what you are looking for. This algorithm is called sequential search. If you do find it, we call this a successful search. If the value is not in the array, eventually you will reach the end. We will call this an unsuccessful search. Here is a simple implementation for sequential search.
// Return the position of an element in an array A.
// If the element is not found, return `null`.
function sequentialSearch(arr, val) -> Int:
for i in 0 .. arr.size - 1: // For each element in A,
if arr[i] == val: // if we found it
return i // return this position.
return null // Otherwise, return null
It is natural to ask how long a program or algorithm will take to run. But we do not really care exactly how long a particular program will run on a particular computer. We just want some sort of estimate that will let us compare one approach to solving a problem with another. This is the basic idea of algorithm analysis. In the case of sequential search, it is easy to see that if the value is in position of the array, then sequential search will look at values to find it. If the value is not in the array at all, then we must look at all array values. This would be called the worst case for sequential search. Since the amount of work is proportional to the size of the array, we say that the worst case for sequential search has linear cost. For this reason, the sequential search algorithm is sometimes called linear search.
1.6.1 Binary search
Sequential search is the best that we can do when trying to find a value in an unsorted array. But if the array is sorted in increasing order by value, then we can do much better. We use an algorithm called binary search.
Let’s say we search for the value in an array. Binary search begins by examining the value in the middle position of the array; call this position and the corresponding value . If , then processing can stop immediately. In this case we are lucky, if not, knowing the middle value provides useful information that can help guide the search process. In particular, if , then you know that the value cannot appear in the array at any position greater than . Thus, you can eliminate future search in the upper half of the array. Conversely, if , then you know that you can ignore all positions in the array less than . Either way, half of the positions are eliminated from further consideration. Binary search next looks at the middle position in that part of the array where value may exist. The value at this position again allows us to eliminate half of the remaining positions from consideration. This process repeats until either the desired value is found, or there are no positions remaining in the array that might contain the value .
Here is the method in pseudocode:
function binarySearch(arr, val) -> Int:
= 0
low = arr.size - 1
high while low <= high: // Stop when low and high meet.
Int = (low + high) / 2 // Integer division
mid: if arr[mid] < val: // Check middle of subarray.
= mid + 1 // In upper half.
low else if arr[mid] > val:
= mid - 1 // In lower half.
high else:
return mid // Found it!
return null // Search value not in array.
And here is an illustration of the binary search algorithm.
With the right math techniques, it is not too hard to show that the cost of binary search on an array of values is at most . This is because we are repeatedly splitting the size of the subarray that we must look at in half. We stop (in the worst case) when we reach a subarray of size 1. And we can only cut the value of in half times before we reach 1.
Variations
Binary search is designed to find the (single) occurrence of a value and return its position. A special value is returned if the value does not appear in the array. The algorithm can be modified to implement variations such as returning the position of the first occurrence of the value in the array if multiple occurrences are allowed. Another variation is returning the position of the greatest value less than the value we are looking for when it is not in the array.
Binary search exercise
Binary search exercise