二分查找详解
有序数组,查找target。
重点关注:
right = a.length
和right = a.length-1
while (left < right)
和while (left <= right)
left = mid + 1
,right = mid
和left = mid + 1
,right = mid - 1
public static void main(String[] args) {
int[] a = {-1, 0, 3, 5, 9, 12, 10};
int target = 9;
int left = 0;
int right = a.length-1; //right指向数组最后一个元素
while (left <= right) { //left左边<target,right右边大于target;快要结束的时候,如果left和right指向了同一个,那么mid也指向这个地方,由于left和right都没有和target比过,所以需要进入while循环再比一次
int mid = (left + right) / 2;
if (a[mid] == target) {
System.out.println(mid);
break;
} else if (a[mid] < target) {
left = mid + 1; //left左边<target,因此+1
} else if (a[mid] > target) {
right = mid - 1; //right右边大于target,因此-1,两句话都使得a[mid]和target的比较没有浪费
}
}
}
public static void main(String[] args) {
int[] a = {-1, 0, 3, 5, 9, 12, 10};
int target = 9;
int left = 0;
int right = a.length; //right指向数组最后一个元素 的 外面第一个
while (left < right) { //left是指向 待比较区间的 最左边,right是指向 待比较区间 右边的 外面,不会重叠
int mid = (left + right) / 2;
if (a[mid] == target) {
System.out.println(mid);
break;
} else if (a[mid] < target) {
left = mid + 1; //mid指向的值已经比target小了
} else if (a[mid] > target) {
right = mid; //mid指向的值已经比target大了,刚好可以做 开区间right值
}
}
}
第一种方法更直观。
mid
值,跟除法的向下取整还是向上取整有关系,但是不影响查找,反正都是从待查找区间的中间找。
其他优化:
int mid = (left + right) / 2
写成int mid = (left + right) >> 1
,使用位运算更快。- 再改进成
int mid = left + ((right-left) >> 1)
,防止left+right
过大,溢出。 - 一开始判断target是否在 有序数组的范围 里面。