JAVA算法----二分查找浅析

1.二分查找的简单介绍

二分查找又名折半查找,是在有序序列中高速寻找所需元素的算法。

以下图为例。

JAVA算法----二分查找浅析_第1张图片
以该寻找7为例,自然可以看到折半查找的高效之处,序列总数相差的越大,二分查找相对于整体遍历的效率相差的就越多,相对于遍历的O(n)的时间复杂度,折半查找的时间复杂度为log2(n)

当然本次教程不单单说这些,而是讨论下二分查找的细节问题,二分查找的终止条件。

感谢大佬的文章让我学到了很多东西
二分查找从入门到入睡

2.二分查找下标的提前溢出

二分查找是需要计算中间值下标的:

如果你用的是mid = (low + right)/ 2

那么恭喜你!

你和JDK开发者一个水平!

 P : 我写错,大佬写作  =>
= 大佬

咳咳,不扯皮了

到 2006 年的时候,Joshua Bloch 才知道「编程珠玑」中的二分查找实现存在上述整数溢出的问题,此时距离该书出版已经过去了 21 年,直到那时,同样的 bug 在他实现的 JDK 的
binarySearch 里也已经存在了 9 年之久。就因为中间值下标的计算语句是mid = (low + right)/ 2

我举个例子,low = 2

high = 2^32 - 1;

虽然二者都没超过正整数的最大值,但是他们的和却超出正整数最大值上限,导致了提前溢出。

提前溢出的处理方法

  1. mid = left + (lright - low)/ 2
    因为坐标是正的,相当于先处理,再相加。
  2. mid = (low + high) >>> 1;
    位运算实现除以2避免溢出。

3.二分查找的三种中止条件

下面以搜索‘4’为例
3.1. low <= high(相错中止)

while(low <= high){

}

JAVA算法----二分查找浅析_第2张图片

// 模版一「一般」情形4: 小于
class Solution {
    public int search(int[] nums, int target) {
        int l = 0, r = nums.length - 1;
        while(l <= r){
            int c = l + (r - l) / 2;
            if(nums[c] < target) l = c + 1; // #1 更新后l左侧元素「必」小于target
            else r = c - 1; // #2 更新后r右侧「必」大于等于target
        }
        return r; // 处理: 相等/刚好小于/不存在
    }
}


3.2. low < high(相等中止)

while(low < high){

}

JAVA算法----二分查找浅析_第3张图片

// 模版二「相等返回」写法
class Solution {
    public int search(int[] nums, int target) {
        int l = 0, r = nums.length;
        while(l < r){
            int c = l + (r - l) / 2;
            if(nums[c] == target) return c; // 找到目标值直接返回
            else if(nums[c] < target) l = c + 1; // #1 更新后l左侧元素「必」小于target 
            else r = c; // nums[c] > target #2 更新后r及其右侧「必」大于target
        }
        return -1;
    }
}


3.1. low + 1 < high(相邻中止)

while(low + 1 < high){

}

JAVA算法----二分查找浅析_第4张图片

// 模版三「相等返回」写法
class Solution {
    public int search(int[] nums, int target) {
        int l = -1, r = nums.length;
        while(l + 1 < r){
            int c = l + (r - l) / 2;
            if(nums[c] == target) return c; // 找到目标值直接返回
            else if(nums[c] < target) l = c; // #1 更新后l及其左侧元素「必」小于target 
            else r = c; // nums[c] > target #2 更新后r及其右侧「必」大于target
        }
        return -1;
    }
}

你可能感兴趣的:(算法,java,数据结构)