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){

}

在这里插入图片描述

// 模版一「一般」情形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){

}

在这里插入图片描述

// 模版二「相等返回」写法
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){

}

在这里插入图片描述

// 模版三「相等返回」写法
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;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

只会写bug的靓仔

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值