二分查找
步骤:
-
有序数组(这是前提,默认)
-
创建一个最左变量L,一个最右变量R,中间索引M=(L+R)/2(这里要注意,在java中浮点数取整为向下取整,如(3+2)/2=2,也要和4舍5入区分开),循环执行步骤3
-
如果L<=R
-
如果目标值等于下标为M的值,则返回M
-
如果目标值大于下标为M的值,则L=M+1
-
如果目标值小于下标为M的值,则R=M-1
-
-
如果L>R,没找到返回-1
代码:
public class d {
public static void main(String[] args) {
int[] num={23,24,26,36,234,453,2357,123456};
int target=4;
int i = binTree(num, target);
System.out.println(i);
}
public static int binTree(int[] num,int target){
int L=0,R=num.length-1;
while (L<=R){
int M=(L+R)/2;
if (target==num[M]){
return M;
}else if (target<num[M]){
R=M-1;
}else{
L=M+1;
}
}
return -1;
}
}
public static void main(String[] args) {
int a=(Integer.MAX_VALUE+(Integer.MAX_VALUE-1))/2;
System.out.println(a);
}
输出:
-1
不足:当L和R都特别大时就会存在M值大于int类型的最大值,存在整数溢出。
原因:int 类型和Integer包装类型的取值范围都为-2147483648~2147483647,当int的值大于2147483647或小于-2147483648时就会产生溢出。
方法一:
实际需要的值:(2147483646+2147483647)/2=2,147,483,646
溢出后的值:-1 (L+R)/2
中间索引:L+(R-L)/2 --->L+R/2-L/2--->(L+R)/2 (R-L)/2 两数相减值不会溢出
public static void main(String[] args) {
int a=Integer.MAX_VALUE+(-Integer.MAX_VALU+(Integer.MAX_VALUE-1))/2;
int b=(Integer.MAX_VALUE+(Integer.MAX_VALUE-1))/2;
System.out.println(a);
System.out.println(b);
}
输出:
2147483647
-1
方法二:
因为计算机存储数字都是以补码的形式存储的。所以可以通过移位运算来避免溢出。
举个例子,8位带符号的二进制数运算
01111111+01111111=111111110 127+127=-2 (127+127)/2=127
将结果向右移一位:01111111 ------>127 刚好等于我们想要的值
中间索引:M=(L+R)>>>1
public static void main(String[] args) {
int a=Integer.MAX_VALUE+(-Integer.MAX_VALUE+(Integer.MAX_VALUE-1))/2;
int b=(Integer.MAX_VALUE+(Integer.MAX_VALUE-1))>>>1;
System.out.println(a);
System.out.println(b);
}
2147483647
2147483647