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

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

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

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

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

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

在一个有序数组中,若采用遍历方式查找目标元素,时间复杂度为 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. 三、总结

    更多推荐文章

    查看全部
    • ChinaTextbook:国内全学段 PDF 教材开源项目,免费无水印
    • 无人机视角高速路面损害检测数据集及 YOLOv8 训练方案
    • MySQL 数据类型详解
    • 基于 Spring Boot 与 Vue 的 Web 虚拟卡销售平台实战
    • ToDesk 内置 ToClaw AI 实现科技新闻日报自动化实战
    • 《Agent Runtime 工程化》第五章 上下文工程:5.7 动手任务
    • libgo C++ 协程库使用指南
    • Kurator 云边协同与多集群治理实操指南
    • Spring Boot 微服务架构:独立匹配系统设计及后端对接
    • 前端动画演进:告别 jQuery animate,拥抱现代方案
    • MySQL 主从复制与高可用架构实战
    • MCP、Agent、Skills:AI 时代三大核心概念深度解析
    • Windows 本地部署 Ollama 与 OpenClaw 实现 AI 自动化
    • Python 量化交易实盘部署与风险管理实战
    • Java 对象更新时避免空字段覆盖的几种拷贝方案
    • Spring Cloud Alibaba 微服务架构详解
    • 大模型 Prompt 高效微调技术详解
    • Neo4j 图谱可视化:告别单调灰色,掌握色彩定制
    • Python 爬虫开发与项目实战:从入门到精通指南
    • 链表在内存管理与缓存淘汰中的应用

    相关免费在线工具

    • 加密/解密文本

      使用加密算法(如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