二分查找(含有动画展示):不再写出死循环

目录

二分查找的动画展示

https://codepen.io/Vitello-Fazenbaker/pen/MYjNPQM

一、为什么需要二分查找?

二,原理展示请打开链接(同上)

https://codepen.io/Vitello-Fazenbaker/pen/MYjNPQM

三、两种写法的对比

四、复杂度分析

五、高频易错点

[❌ 错误一:mid 计算用加法可能整数溢出](#❌ 错误一:mid 计算用加法可能整数溢出)

[❌ 错误二:区间混用导致死循环](#❌ 错误二:区间混用导致死循环)

[❌ 错误三:前提条件忘记了](#❌ 错误三:前提条件忘记了)

六、面试爱考的变种

七、总结


二分查找的动画展示

https://codepen.io/Vitello-Fazenbaker/pen/MYjNPQM


一、为什么需要二分查找?

假设你要在一本 1000 页的字典里找到 "Zebra" 这个单词。

方法一:从第 1 页翻到第 1000 页,一页一页找 → 最坏要翻 1000 次。

方法二:翻到第 500 页,发现字母比 Z 小,就只在后半本找;再翻到第 750 页......每次淘汰一半,最多翻 10 次就找到了。

方法二就是二分查找的本质:每次把搜索范围缩小一半,效率是线性查找的指数级提升。


二,原理展示请打开链接(同上)

https://codepen.io/Vitello-Fazenbaker/pen/MYjNPQM


三、两种写法的对比

二分查找有两种常见写法,区别只在区间的定义方式。搞清楚这个,就不会再写出死循环了。

对比点 写法一:闭区间 [begin, end] 写法二:左闭右开 [begin, end)
end 初始值 n - 1(最后一个元素) n(越界一位,代表"不存在")
while 条件 begin <= end(等号允许,单元素也要查) begin < end(等号不允许,[x,x) 是空区间)
目标在左半边时 end = mid - 1 end = mid(mid 本身已排除)
目标在右半边时 begin = mid + 1 begin = mid + 1

核心原则:**while 条件 和 end 的含义必须统一。**选了哪种区间定义,两处都要对应,否则必出 bug。

复制代码
int BinarySearch(int* a, int n, int x)
{
    int begin = 0;
    int end = n - 1; // end 指向最后一个元素

    while (begin <= end) // ← 等号:单元素区间也要处理
    {
        int mid = begin + ((end - begin) >> 1);
        if (x < a[mid])
            end = mid - 1; // ← -1:mid 已经比较过了,排除
        else if (x > a[mid])
            begin = mid + 1;
        else
            return mid;
    }
    return -1;
}

四、复杂度分析

时间复杂度(平均 / 最坏)

O(log n)

每次砍掉一半,n=10亿 最多也只需要 30 次比较

时间复杂度(最好)

O(1)

第一次 mid 就命中目标

空间复杂度

O(1)

只用了几个变量,不需要额外内存


五、高频易错点

❌ 错误一:mid 计算用加法可能整数溢出

不要写 mid = (begin + end) / 2,当 begin 和 end 都很大时,加法会溢出。

正确写法:mid = begin + (end - begin) / 2,或者用位运算 >> 1 替代除以 2(效果一样,但不要为了优化强行用,可读性更重要)。

❌ 错误二:区间混用导致死循环

比如用了闭区间,while 写 begin < end(少了等号),当 begin == end 时会直接跳出,漏掉最后一个元素。

❌ 错误三:前提条件忘记了

二分查找要求数组必须是有序的。如果数组无序,结果完全错误,且不会报错,是最难排查的 bug 之一。


六、面试爱考的变种

查找左边界

目标值可能重复出现,找最左边那个的下标。找到 mid==x 后不要直接返回,继续往左缩。

查找右边界

找最右边那个,找到后不返回,继续往右缩,最终返回 end。

旋转数组二分

数组被旋转过(如 [4,5,1,2,3]),每次判断哪半边是有序的,只在有序那边收缩。

实数域二分

不找下标,找满足某个条件的实数值,比如开平方根。while 条件改为 end - begin > 1e-6

答案二分

不在数据上二分,而是在"答案的值域"上二分,配合 check() 函数验证答案是否合法。

std::lower_bound

C++ STL 自带,返回第一个 >= 目标值的迭代器。面试时可以直接用,不用自己实现。


七、总结

二分查找的所有 bug,90% 来自区间定义不统一。
记住一条原则:确定区间类型(闭/左闭右开),然后 end 的初值、while 条件、end 的收缩方式,三处严格对应。

相关推荐
XiYang-DING1 小时前
【Java EE】阻塞队列(BlockingQueue)
java·java-ee
山甫aa1 小时前
多叉树定义与遍历-----从零开始的数据结构
开发语言·c++·二叉树·多叉树
永远睡不够的入1 小时前
C++11新特性(2):深入 C++ 参数传递黑盒:从引用折叠到完美转发,再到可变参数模板
开发语言·c++
AndreasEmil2 小时前
基于多设计模式的抽奖系统 - 测试报告
java·selenium·设计模式·postman
无限进步_2 小时前
【C++】寻找数组中出现次数超过一半的数字:三种解法深度剖析
开发语言·c++·git·算法·leetcode·github·visual studio
深邃-2 小时前
【Web安全】-Kali,Linux配置(1):Kali网络配置,LinuxEnvConfig配置脚本,APT源的讲解,Kali设置中文
linux·运维·开发语言·网络·安全·web安全·网络安全
Hello World . .2 小时前
Linux驱动编程:内核同步的艺术-从互斥到底半部
linux·开发语言·数据库
江山与紫云2 小时前
告别重复造轮子:Codex写脚本
开发语言·python
星轨zb2 小时前
什么是Spring设计模式:单例、工厂与代理
java·spring·设计模式
覆东流2 小时前
第8天:python列表基础
开发语言·python