Efficiency of the Binary Search

advertisement
Binary Search
The simplest method for searching an array for a specific value (called the search value): The
Linear search. If the content of the array is unsorted it is the only method that can be used, and
the potential exists that the search value may need to be compared to every element in the array
before we can determine whether or not it is present in the array. If we are searching for a
value that is not there, then we won’t know for sure until the search value is compared to the
last element. If the array is sorted in ascending order, then we can stop performing comparisons
once a value is found that is greater than the search value, somewhat improving the algorithm.
But still in the worst case (the search value > value stored in the last element), then we would
still need to visit all elements in the array. Assuming that the array has N elements this makes
the linear search O(N).
The binary search algorithm is a far better method for searching that takes advantage of the fact
that the array is sorted. It uses a divide and conquer strategy, where the size of the array being
searched is divided in half with each comparison. It can be implemented using either iteration or
recursion. Suppose that we have an array of N integers sorted in ascending order.
3
5
7
9
10 12 17 20 24 29 31 37 44 50 62 71 72 80 93 100
1
N
0
1
2
3
4
5
6
7
8
9
10 11 12 13 14 15 16 17 18
19
Suppose the value we seek is 80. We call the method with the index number of the first and last
elements in the range of elements we are still considering. We begin our search at the middle
element of the array which is (first+last)/2. In our example N=19, we calculate (19+0)/2 = 9.
We compare our search value to the value stored in the 9th element of the array which is 29.
29 is less than 80. This means that the value we seek must like between elements 10 and 19. So
we need only concern ourselves with the upper portion of the array, and we set “first” to mid
index +1 or 10 in this case
31
37
44
50
62
71
72
80
93
100
10
11
12
13
14
15
16
17
18
19
Now we determine the middle element of this portion of the array: (10+19)/2 = 14
Element 14 contains the value 62 which again is less that 80, so element 15 becomes the “lower
bounds” of the elements that might contain our value.
71
72
80
93
100
15
16
17
18
19
We determine the middle again which is (15 + 19)/2 which is 17.. and the value in element 17 is
80, we have found the desired value and can return 17 as the result of our search.
If the value we are searching for is not in the array, then eventually we will end up looking at a
portion of the array that consists of a single element, if it does not match our search value we
know that the value is not in the array and we can simply return a value (-1 ) indicating that the
value was not found, also we have to insure that the index of the “first” element is never greater
than the index of the “last”
It is plain that the binary search algorithm yields a significant improvement over the linear
search. A linear search would have performed 18 comparisons before finding our value, while
the binary search performed only 3.
So how can we implement this algorithm in code? Consider the following, assume the array is
named arr, and our search value is contained in a variable named val:
1) With each comparison, we are looking at a range of elements in the array. We can
indicate these elements by specifying a low and high index value that indicates the first
and last element in the range being considered. In the first search, low=0 and high = N1, since we are considering the entire array.
2) We compute the middle index as mid = (low + high)/2
3) if val = arr[mid] then return mid
4) if low = high or low > high return -1.. the value is not found
5) if val < arr[mid] our search value must be to the left of the middle element, so set high
= mid -1 , and search again
6) if val > arr[mid] our search value must be to the right of the middle element, so set low
= mid +1, and search again
It should be obvious that the binary search algorithm can be easily implemented as a recursive
method.
public static int bsearch(int[] arr, int low, int high, int searchVal) {
/* The binary search algorithm returns the index number of the array
Element which contains the search value, or -1 if the value is not in
The array */
int result, mid;
mid = (low + high) / 2;
if (arr[mid] == searchVal) result = mid;
else if (low >= high) result = -1;
else if ( searchVal < arr[mid] )
result = bsearch(arr, low, mid-1, searchVal);
else result = bsearch(arr, mid + 1, high, searchVal);
return result;
}// end bsearch
A complete application using this algorithm along with the bubble sort is:
import java.util.Scanner;
public class bsearch {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int numelements;
char exit = ' ';
int searchValue, result;
// The following section of code, declares and fills an array of N elements
System.out.println("Please enter the number of elements in the array.");
numelements = in.nextInt();
int[] intArr = new int[numelements];
for(int i=0; i< numelements; i++){
System.out.println("Please enter a value for element " + i);
intArr[i] = in.nextInt();
}
// Sort the array so we can search efficiently, then print it out
bubble(intArr);
System.out.println("The sorted array is: ");
for(int i=0; i< numelements; i++)
System.out.print(intArr[i] + " ");
System.out.println();
// in a loop, prompt the user for a value to search for, then search the array
// and indicate if the value was found or not
while (exit != 'n' && exit != 'N') {
System.out.println("please enter a value to search for ");
searchValue = in.nextInt();
result = bsearch(intArr, 0, numelements-1, searchValue);
if (result == -1)
System.out.println("The value " + searchValue +
" is not in the array.");
else
System.out.println("The value " + searchValue + " is in element "
+ result);
System.out.println("Enter Y to search again, N to exit.");
exit = (in.next()).charAt(0);
}// end while
}// end main
public static void bubble(int[] arr) {
int temp;
for (int i=0; i< arr.length; i++){
for (int j=0; j< arr.length-1; j++){
if( arr[j] > arr[j+1]) {
temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}// end swap
}// end inner for
}// end outter for
} // end bubble
public static int bsearch(int[] arr, int low, int high, int searchVal) {
int result, mid;
mid = (low + high) / 2;
if (arr[mid] == searchVal) result = mid;
else if (low >= high) result = -1;
else if ( searchVal < arr[mid] )
result = bsearch(arr, low, mid-1, searchVal);
else result = bsearch(arr, mid + 1, high, searchVal);
return result;
}// end bsearch
}
Iterative Binary Search
The binary search algorithm can also be implemented using iteration (looping) instead of
recursion:
public static int bsearch(int[] arr, int searchVal) {
int result=-1, mid;
boolean found=false;
int low=0, high = arr.length-1;
while (!found && low <= high) {
mid = (low + high) / 2;
if (arr[mid] == searchVal) {
result = mid;
found = true;
}
else if ( searchVal < arr[mid] )
high = mid-1;
else low = mid + 1;
} // end while
return result;
}// end bsearch
Efficiency of the Binary Search
One determine the maximum # of comparisons the binary search will perform before
determining that a value is not present in the array can be determined by dividing the # of
elements in the array by 2 until the # of elements remaining in the search area is zero.
So if we have 2000 elements 1000, 500, 250, 125, 62, 31, 15, 7, 3, 1, 0 or 11 comparisons,
The maximum # of comparisons needed performed by the binary search algorithm for can be
calculated as the first power of 2 greater than the # of elements in the array, which is log2 n.
For the previous example
210 = 1024
and 211 = 2048
With means that the big O notation for the binary search is O(log n)
Download