The binary search employs two integer variables to indicate the search space; one records the starting index of the search space, and the other variable records the ending index of the search space. Initially, the search space is the complete array, as shown in the following illustration. The start index of the search space is 0, and the end index is one less than the array’s length. We find the mid (middle element index) of the search space so that we can compare the searched number with the middle element in the search space. This helps reduce the search space to either the left part (the end index moves to the index one less than the mid) or the right part (the start index moves to the index one greater than the mid) of the middle element.
To find the middle element index, the first method that comes to our mind is to sum up the start and end indices of the search space and divide the sum by 2.
This method seems to work because we usually consider small-size arrays. Now assume we have a very large array of size greater than half of the maximum INT value (2147483647). If each time the search space reduces to the right part of the middle element, the start and the end pointer reach the last indices in the array, which are very large, greater than half of the maximum INT value (2147483647). Adding two index values (start and end) that are greater than half of the maximum INT value (2147483647) will exceed the maximum INT value. As a result, the sum (start + end) overflows to a negative value and will remain negative after dividing by 2. The negative index couldn’t be found in the array, and we'll get an index out of bound error.
Following is another way to calculate the middle element index. This approach gives a positive index value unless the size of the array exceeds the maximum value of the INT.
The following is a code example for this approach:
#include <climits>#include <iostream>#include <cmath>using namespace std;int main() {cout << "Minimum int value(INT_MIN)= " << INT_MIN << endl;cout << "Maximum int value(INT_MAX)= " << INT_MAX << endl;cout << "Half of the maximum int value = INT_MAX/2 = " << INT_MAX/2 << endl;int sizeofArr = (ceil(INT_MAX/2)) + 10; // Making array size greater than half of the maximum int valuecout << "Size of array (Ten greater than half of the Maximum int value)= " << sizeofArr << endl << endl;int start=1073741830; //The start index reached the 1073741830'th index of the arrayint end=sizeofArr-1; //The end index is at the last index of the arraycout << "Assume the 'start' index has reached 1073741830'th index of the array." << endl;cout << "Assume the 'end' is at the last index of the array = sizeofArr-1 = " << sizeofArr-1 << endl << endl;int mid = (start + end)/2; //Finding middle element index using the greedy approachcout << "Middle element index found with greedy approach((start + end)/2): "<< mid << endl; // Greedy approach gives negative mid index, which is not in the array indices range, so if we access the array element at this mid index, then we will get an index out of bound errormid = start + ((end - start) / 2); //Finding middle element index using the best approachcout << "Middle element index found with best approach(start + ((end - start) / 2)): "<< mid << endl; // The best approach gives a positive index value unless the size of the array exceeds the maximum value of the INTreturn 0;}
Run the above code and analyze the difference between the middle index found with the greedy and best approaches. With the greedy approach, we get a negative index that doesn’t exist in the array, while with the best approach, we find the correct middle index.
Free Resources