7.1. Searching in an Array¶
7.1.1. Searching in an Array¶
7.1.1.1. Sequential Search¶
If you want to find the position in an unsorted array of \(n\) integers that stores a particular value, you cannot really do better than simply looking through the array from the beginning and move 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 array A with value K.
// If K is not in A, return A.length.
static int sequential(int[] A, int K) {
for (int i=0; i<A.length; i++) // For each element
if (A[i] == K) // if we found it
return i; // return this position
return A.length; // Otherwise, return the array length
}
// Return the position of an element in array A with value K.
// If K is not in A, return A.length.
static int sequential(int[] A, int K) {
for (int i=0; i<A.length; i++) { // For each element
if (A[i] == K) { // if we found it
return i; // return this position
}
}
return A.length; // Otherwise, return the array length
}
// Find the position in A that holds value K, if any does
int sequential(int A[], int size, int K) {
for (int i=1; i<size; i++) // For each element
if (A[i] == K) // if we found it
return i; // return this position
return size; // Otherwise, return the array length
}
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 \(i\) of the array, then sequential search will look at \(i\) values to find it. If the value is not in the array at all, then we must look at \(n\) values if the array holds \(n\) values. This would be called the worst case for sequential search. Since the amount of work is proportional to \(n\), we say that the worst case for sequential search has linear cost. For this reason, the sequential search algorithm is sometimes called linear search.
7.1.1.2. Binary Search¶
Sequential search is the best that we can do when trying to find a value in an unsorted array. [1] But if the array is sorted in increasing order by value, then we can do much better. We use a process called binary search.
Binary search begins by examining the value in the middle position of the array; call this position \(mid\) and the corresponding value \(k_{mid}\). If \(k_{mid} = K\), then processing can stop immediately. This is unlikely to be the case, however. Fortunately, knowing the middle value provides useful information that can help guide the search process. In particular, if \(k_{mid} > K\), then you know that the value \(K\) cannot appear in the array at any position greater than \(mid\). Thus, you can eliminate future search in the upper half of the array. Conversely, if \(k_{mid} < K\), then you know that you can ignore all positions in the array less than \(mid\). 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 \(K\) 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 \(K\). Here is an illustration of the binary search method.
With the right math techniques, it is not too hard to show that the cost of binary search on an array of \(n\) values is at most \(\log n\). 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 \(n\) in half \(\log n\) times before we reach 1. [2]