问题引出:
public static void main(String[] args)
{
int arr[] = {1, 2, 3, 4, 5};
int refen = Refen(arr, 4);
System.out.println(refen);
}
private static int Refen(int arr[], int value)
{
int left = 0;
int right = arr.length - 1;
int mid = 0;
while(left < right)
{
mid = (left + right) >> 1;
if(arr[mid] < value)
{
left = mid + 1;
}else if(arr[mid] > value)
{
right = mid - 1;
}else
{
return mid;
}
}
return -1;
}
打印结果:
3
但是我们这样写会有错误的如下:
public static void main(String[] args)
{
int i = 0;
int j = Integer.MAX_VALUE - 1;
int m = (i + j) / 2;
System.out.println(m); // 输出结果:1073741823
// 如果目标在中间值的右侧,那么就需要扩大左边键
i = m + 1;
m = (i + j) / 2;
System.out.println(m); // 输出结果:-536870913
/**
* 因为第一次计算出的m取值 已经比较大了,它如果再去加上j
* 这样就超过了正整数能表示的范围 , 就由正变为了负数
*/
}
打印结果:
1073741823
-536870913
当中间值经过两个Integer最大值的相加后就会超出 整数类型的最大存储空间,从而导致变为负数
那么我们该如何解决这个问题呢?
我们可以使用无符号右移运算来解决这个问题:
public static void main(String[] args)
{
int i = 0;
int j = Integer.MAX_VALUE - 1;
int m = (i + j) / 2;
System.out.println(m); // 输出结果:1073741823
// 如果目标在中间值的右侧,那么就需要扩大左边键
i = m + 1;
m = (i + j) >>> 1;
System.out.println(m); // 输出结果:1610612735
/**
* 因为第一次计算出的m取值 已经比较大了,它如果再去加上j
* 这样就超过了正整数能表示的范围 , 就由正变为了负数
*/
}
打印结果:
1073741823
1610612735
除2运算不会改变二进制的数
这个方式在其它语言中同样使用比如JavaScript,它会自动进行取整