第1章:二分查找

155 阅读2分钟

第1章:二分查找

1 代码实现

public boolen binSearch(int[] numbers, int target){
    
    //判断数组是否为空
    if(numbers == null) return false;
    
    //定义初始最小、最大索引
    int low = 0;
    int high = numbers.length - 1;
    
    //确保不会出现重复查找,越界
    while(low <= high){
        
        //计算出中间索引值
        //int mid = (end + start)>>>1 ;//防止溢出
        int mid = (high - low)/2 + low;//防止溢出
        
        if(numbers[mid] == target){
            //查找成功返回
            return true;
        }
        else(numbers[mid] > target){
            //继续在R[low..mid-1]中查找
            high = mid - 1;
        }
        else{
            //继续在R[mid+1..high]中查找
            low = mid + 1;
        }
        
    }
    
    return false;  
}

2.注意细节

(1) 使用(low+high)/2会有整数溢出的问题

(问题会出现在当low+high的结果大于表达式结果类型所能表示的最大值时,这样,产生溢出后再/2是不会产生正确结果的,而low+((high-low)/2)不存在这个问题

(2) int middle = start + (end - start) >> 1;

  • 此处的右移可以替换成除2的方式,因为不会有溢出的问题。但右移的效率更高

  • 这种计算方法其实是在直观思维的基础之上做了转换

  • 直观思维是相加除2直接求中间值,

  • 这种计算方式等于是根据起始值或结束值如何得到中间值

  • 这样描述似乎很乱,举个栗子就是假设起始值是2,结束值是6,我们可以很容易的求出中间值为4。但其实这个

  • 是指针对起点0来说。对于起始值呢,这个4就是起始值加2得到的。这个加的2是通过结束值-起始值,然后除2得到的。

  • 根据java向下取整的计算方式,我们不能用结束值减去差值的方式得到中间值

(3) int middle = (end + start) >>> 1;

  • 这种计算方式加法会溢出,但无符号右移保证了计算的正确性

  • 无符号右移后高位补0,不会得到负数

3 其他

public static void main(String[] args) {

    int low = Integer.MAX_VALUE;
    int high = Integer.MAX_VALUE;
    
    System.out.println(low);//2147483647
    System.out.println(high);//2147483647
    System.out.println(low + high);//-2
    
    System.out.println("---------");
    System.out.println((low + high)/2);//-1
    System.out.println((low + high)>>2);//-1
    System.out.println((low + high)>>>2);//2147483647
    System.out.println((high - low)/2 + low);//2147483647
}

// 但没有<<<