跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客我的书GitHub 精选镜像AI 生图工具UI配色美学关于
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
C++算法

二分查找算法详解:核心原理与实战应用

二分查找通过不断缩小搜索范围实现 O(log n) 高效查询。深入剖析算法细节,涵盖左右边界更新、中点选择策略及循环条件设计,重点讲解如何避免死循环。结合基础查找、区间定位、平方根计算、山脉数组峰顶及缺失数字检测五个实战案例,展示 C++ 代码实现中的边界优化与溢出防护技巧,帮助读者掌握二分法在有序及具备二段性场景下的应用逻辑。

片刻发布于 2026/3/23更新于 2026/8/739 浏览
二分查找算法详解:核心原理与实战应用

二分查找算法详解:核心原理与实战应用

二分查找是一种经典的高效查询方法,其核心思想是通过不断将查找范围缩小为一半,从而大幅降低时间复杂度。

在一个有序数组中,若采用遍历方式查找目标元素,时间复杂度为 O(n)。而使用二分算法,每次从待遍历数组的中心位置开始判断:

  • 若当前值小于目标值,说明目标在右区间,更新左边界;
  • 若当前值大于目标值,说明目标在左区间,更新右边界。

文章配图

最坏情况下只需遍历 log(n) 次。这意味着在 100 万个数中查找目标元素最多只需要 20 次,效率提升显著。

一、算法细节与陷阱

二分算法的本质不难理解,但在具体落地时,细节处理往往决定了代码的正确性。

1. 左右临界点更新

我们需要 left 和 right 指针标记区间边界,每次迭代后需根据比较结果更新。

  • 目标元素不重复:直接移动边界即可,例如 right = mid - 1。
  • 连续序列的左端点:若 cur >= 目标值,cur 可能是结果,需保留当前位置,故 right = cur;否则 left = mid + 1。
  • 连续序列的右端点:若 cur <= 目标值,cur 可能是结果,故 left = cur;否则 right = mid - 1。

文章配图

2. 中点选择策略

当区间长度为偶数时,中点有两个可选位置(左中点或右中点)。

  • 基础查找:不影响结果,任选其一。
  • 查找左端点:需选 左中点。若选右中点且 mid >= target,可能导致 right 不变,陷入死循环。
  • 查找右端点:需选 右中点。同理可避免死循环。

文章配图

3. 循环条件设计

是 left < right 还是 left <= right?这取决于相遇后是否还需判断。

  • 基础查找:相遇后仍需判断该位置是否为目标值,故用 left <= right。
  • 边界查找:相遇后若值为目标值,指针可能停滞导致死循环,故用 left < right,并在循环外额外判断一次。
  • ❓ 必须是有序数组吗?

    ✅ 不一定。只要数据具备'二段性'(即满足某种单调性质),即使整体无序也可使用二分。

    二、典型场景实战

    1. 基础二分查找

    题目:给定升序数组 nums 和目标值 target,返回下标,不存在则返回 -1。

    思路:标准模板,注意 mid 更新时机。

    class Solution {
    public:
        int search(vector<int>& nums, int target) {
            int left = 0, right = nums.size() - 1;
            while (left <= right) {
                int mid = left + (right - left) / 2;
                if (nums[mid] > target) {
                    right = mid - 1;
                } else if (nums[mid] < target) {
                    left = mid + 1;
                } else {
                    return mid;
                }
            }
            return -1;
        }
    };
    

    2. 查找元素的第一个和最后一个位置

    题目:在非递减数组中找出目标值的起始和结束位置。

    思路:分别调用两次二分查找,一次找左边界,一次找右边界。

    class Solution {
    public:
        vector<int> searchRange(vector<int>& nums, int target) {
            if (nums.empty()) return {-1, -1};
            
            // 查找左边界
            int left = 0, right = nums.size() - 1;
            while (left < right) {
                int mid = left + (right - left) / 2;
                if (nums[mid] >= target) right = mid;
                else left = mid + 1;
            }
            
            vector<int> ret = {-1, -1};
            if (nums[left] == target) ret[0] = left;
            
            // 查找右边界
            left = 0; right = nums.size() - 1;
            while (left < right) {
                int mid = left + (right - left + 1) / 2;
                if (nums[mid] <= target) left = mid;
                else right = mid - 1;
            }
            
            if (nums[right] == target) ret[1] = right;
            return ret;
        }
    };
    

    3. x 的平方根

    题目:计算非负整数 x 的算术平方根,只保留整数部分。

    思路:无需构建数组,直接在 [1, x] 范围内二分。注意防止乘法溢出。

    class Solution {
    public:
        int mySqrt(int x) {
            if (x == 0) return 0;
            long long left = 1, right = x;
            while (left < right) {
                long long mid = left + (right - left + 1) / 2;
                if (mid * mid > x) right = mid - 1;
                else left = mid;
            }
            return left;
        }
    };
    

    4. 山脉数组的峰顶索引

    题目:在递增后递减的数组中找到峰值下标。

    思路:虽然数组不完全有序,但具有'先增后减'的二段性。寻找递增区间的右端点即可。

    class Solution {
    public:
        int peakIndexInMountainArray(vector<int>& arr) {
            int left = 0, right = arr.size() - 1;
            while (left < right) {
                int mid = left + (right - left + 1) / 2;
                if (arr[mid] > arr[mid - 1]) left = mid;
                else right = mid - 1;
            }
            return left;
        }
    };
    

    5. 点名(缺失数字)

    题目:学号 0 ~ n-1 的升序数组中,仅有一位同学缺席,返回其学号。

    思路:若 records[i] == i,说明前半部分无缺失;反之缺失在前半部分。本质是找分界点。

    class Solution {
    public:
        int takeAttendance(vector<int>& r) {
            if (r[0] != 0) return 0;
            int left = 0, right = r.size() - 1;
            while (left < right) {
                int mid = left + (right - left + 1) / 2;
                if (r[mid] > mid) right = mid - 1;
                else left = mid;
            }
            return left + 1;
        }
    };
    

    三、总结

    二分查找的核心在于将搜索空间减半,将复杂度优化至 O(log n)。实际应用中需注意三点:

    1. 边界更新:明确是包含当前点还是排除当前点,决定 +1 或 -1。
    2. 中点选取:配合边界更新策略,防止死循环。
    3. 循环条件:根据是否需要处理 left == right 的情况选择 < 或 <=。

    掌握这些细节后,二分法不仅适用于有序数组,还能灵活应用于具备单调性或二段性的各类场景中。

    目录

    1. 二分查找算法详解:核心原理与实战应用
    2. 一、算法细节与陷阱
    3. 1. 左右临界点更新
    4. 2. 中点选择策略
    5. 3. 循环条件设计
    6. 二、典型场景实战
    7. 1. 基础二分查找
    8. 2. 查找元素的第一个和最后一个位置
    9. 3. x 的平方根
    10. 4. 山脉数组的峰顶索引
    11. 5. 点名(缺失数字)
    12. 三、总结
    • 免费图片AI生成工具免费生成了解详情
    • Magick API 一键接入全球大模型注册送1000万token查看
    • 免费图片视频在线生成30秒,将你的创意变成现实开始设计
    • X/Twitter免费视频下载器免登陆无限额度免费视频解析下载了解详情
    • 100+免费在线小游戏爽一把
    极客日志微信公众号二维码

    微信扫一扫,关注极客日志

    微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

    更多推荐文章

    查看全部
    • 前端大数据导出优化:解决 Chrome 内存崩溃的实战方案
    • 前端 EME DRM 反录屏原理及实战代码
    • Leather Dress Collection 基于 Stable Diffusion 1.5 的皮革服装 LoRA 实践
    • 利用 Fiddler 代理抓包 JVM 发出的 HTTP 请求
    • 使用 ChatGPT 降低毕业论文 AIGC 检测率的实操方法
    • 算法实战:位运算解决两数之和与唯一数字问题
    • LLaMA Factory 微调古汉语特化大模型
    • Quest 一体机 SideQuest 安装 APK 与 OBB 数据包教程
    • 基于 OpenClaw 与飞书搭建 AI 新闻推送机器人
    • DeepSeek 大模型在云平台的优化实践与应用落地
    • Python 纪念币预约自动化工具配置指南
    • GitHub 代码下载失败问题解决方案
    • Python 实现 MCP 客户端调用高德地图天气查询
    • OpenClaw 全平台卸载指南:Windows、macOS、Linux 及包管理器清理
    • OpenClaw 接入飞书配置教程
    • Flutter pathfinding 库在 OpenHarmony 上的适配实战与性能优化
    • C++ 函数指针与回调函数深度解析
    • 字符串算法实战:公共前缀、回文子串与运算
    • 毕业论文 AI 辅助写作全流程实操指南
    • 数组算法总结:二分查找、快慢指针、双指针与滑动窗口

    相关免费在线工具

    • 加密/解密文本

      使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online

    • Gemini 图片去水印

      基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online

    • Base64 字符串编码/解码

      将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

    • Base64 文件转换器

      将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online

    • Markdown转HTML

      将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online

    • HTML转Markdown

      将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online