二分查找算法

259 阅读1分钟
  • 前提条件
    • 对于进行查找的数组是有序的
  • 二分查找流程
    • 定义左边界L,右边界R,确定当前的搜索范围,循环进行二分查找
    • 获取当前搜索范围的中间索引mid = (L + R) / 2
    • 将数组arr[mid]与目标值target进行比较
      • 如果arr[mid] > target,说明当前目标值在中间索引的左侧,将右边界R = mid - 1,重新确定当前查找范围
      • 如果arr[mid] < target,说明当前目标值在中间索引的右侧,将左边界L = mid + 1,重新确定当前查找范围
      • 如果arr[mid] = target,返回当前中间索引mid
    • 当L > R时,表示当前数组中没有找到目标值,应返回-1
  • 代码演示
public static void main(String[] args) {
    int[] arr = new int[]{2, 5, 7, 8, 9, 22, 35, 46, 65, 76, 79, 83, 87, 88, 99, 567};
    int target = 35;
    int index = binarySearch(arr, target);
    System.out.println(index);
}

public static int binarySearch(int[] arr, int target) {
    //定义数组的左边界
    int l = 0;
    //定义数组的右边界
    int r = arr.length - 1;
    //定义中间值
    int mid;
    //当左边界超过右边界时,结束循环
    while (l <= r) {
        //获取中间索引
        mid = (l + r) / 2;
        //如果中间索引的值大于目标值,表示目标值的范围为中间索引的左侧。将右边界 = mid - 1
        if (arr[mid] > target) {
            r = mid - 1;
        }
        //如果中间索引的值小于目标值,表示目标值的范围为中间索引的左侧。将左边界 = mid + 1
        else if (arr[mid] < target) {
            l = mid + 1;
        }
        //如果中间索引的值与目标值相等,返回当前索引
        else {
            return mid;
        }
    }
    //没有找到返回-1
    return -1;
}
  • 整数溢出问题
    • 在上述代码中,计算中间索引时mid = (L + R) / 2,可能会导致整数溢出问题,计算的mid值为负数
    • 当数组的长度过大时,对于R = Integer.MAX_VALUE时,并且目标值target在中间索引mid的右侧,在下一次计算中mid值会出现负数
  • 解决整数溢出问题
    • 将mid = (L + R) / 2替换为 L + (R - L) / 2
    • 将mid = (L + R) / 2替换为(L + R) >>> 1
    • 第二种方式对比与第一种方式效率会高一些,但只针对正数进行操作,将当前数值向右移动一位