二分查找在具体实现时,while循环的判断条件决定了查找的区间,一般分两种:
1.while(left < right)表示在[left, right)区间中查找,left指向的位置会被访问,而right指向的位置不会被访问;
2.while(left <= right)表示在[left, right]区间中查找,left、right指向的位置都会被访问。
因此,left、right的初值以及while循环体里的分割操作则必须和查找区间对应,两种查找区间对应的代码分别如下:
【第1种】
boolean BinarySearch(int[] array, int target) {
int left = 0, right = array.length, mid;
while (left < right) {
mid = left + (right - left) / 2;
if (target == array[mid]) return true;
if (target < array[mid]) {
right = mid;
continue;
}
left = mid + 1;
}
return false;
}
【第2种】
boolean BinarySearch(int[] array, int target) {
int left = 0, right = array.length - 1, mid;
while (left <= right) {
mid = left + (right - left) / 2;
if (target == array[mid]) return true;
if (target < array[mid]) {
right = mid - 1;
continue;
}
left = mid + 1;
}
return false;
}
以上代码用于判断一个数是否在一个升序排列的数组之中,如果需要返回在升序数组中插入一个数的位置,则代码应为:
int BinarySearch(int[] array, int target) {
int left = 0, right = array.length - 1, mid;
while (left <= right) {
if (array[mid] <= target) left = mid + 1;
else right = mid - 1;
}
return left;
}
其中,语句“if (array[mid] <= target) left = mid + 1;”,它决定了只要array[mid] <= target,left就会右移,因而循环结束时left指向的位置及右侧的数都比target要大,left指向位置的左侧的数都小于或等于target;如果将其改成“if (array[mid] < target) left = mid + 1;”,则循环结束时,left指向的位置及右侧的数都大于或者等于target,left指向位置的左侧的数都小于target。
如果将最后的返回语句改成“return right;”又会得到怎样的结果呢?其实循环结束时,一定有left > right + 1,实际上left的值为right + 1,所以right指向left左边的位置。因而,对于判断条件array[mid] <= target,循环结束时right指向位置及左侧的数都小于或者等于target,right指向位置右侧的数都比target要大;对于判断条件array[mid] < target,循环结束时right指向位置及左侧的数都小于target,right指向位置右侧的数都大于或等于target。