二分查找:迭代与递归实现全解析

一、二分查找的核心原理

二分查找仅适用于有序的数组 / 容器,核心逻辑是:

  1. 定义查找区间 [left, right](闭区间);
  2. 计算区间中点 mid = left + (right - left) / 2(避免 (left+right)/2 导致的整数溢出);
  3. 对比 nums[mid] 与目标值 target,缩小区间:
    • nums[mid] == target:找到目标,返回索引;
    • nums[mid] < target:目标在右半区间,更新 left = mid + 1
    • nums[mid] > target:目标在左半区间,更新 right = mid - 1
  4. left > right 时,区间无效,说明无目标值,返回 -1

二、迭代版实现(基础版)

cpp 复制代码
class Solution {
public:
    int search(vector<int>& nums, int target) {
        int left = 0;
        int right = nums.size() - 1; // 闭区间右边界
        
        while (left <= right) { // 区间有效时循环
            int mid = left + (right - left) / 2; // 安全计算mid
            if (nums[mid] == target) {
                return mid; // 找到目标,直接返回
            } else if (nums[mid] < target) {
                left = mid + 1; // 右半区间,排除mid
            } else {
                right = mid - 1; // 左半区间,排除mid
            }
        }
        return -1; // 未找到目标
    }
};

迭代版关键注意点

  1. 区间边界 :采用闭区间 [left, right],因此循环条件是 left <= right(当 left == right 时,区间仍有一个元素需要检查);
  2. mid 计算left + (right - left) / 2 等价于 (left + right) / 2,但避免了 left + right 超出 int 范围的溢出问题;
  3. 边界更新 :必须用 mid + 1/mid - 1,而非 left + 1/right - 1,否则会退化为顺序查找,失去二分优势。

三、递归版实现(进阶版)

递归版将循环逻辑替换为函数自身调用,核心是 "终止条件 + 缩小区间递归"。

cpp 复制代码
class Solution {
public:
    // 对外接口:保持简洁,初始化递归区间
    int search(vector<int>& nums, int target) {
        return binarySearch(nums, target, 0, nums.size() - 1);
    }

private:
    // 递归辅助函数:承载核心逻辑,传递区间参数
    int binarySearch(vector<int>& nums, int target, int left, int right) {
        // 递归终止条件:区间无效,返回-1
        if (left > right) {
            return -1;
        }
        int mid = left + (right - left) / 2;
        if (nums[mid] == target) {
            return mid;
        } else if (nums[mid] < target) {
            // 递归查找右半区间
            return binarySearch(nums, target, mid + 1, right);
        } else {
            // 递归查找左半区间
            return binarySearch(nums, target, left, mid - 1);
        }
    }
};

递归版核心坑点(新手必看)

  1. 终止条件优先 :必须先判断 left > right,否则会无限递归导致栈溢出;
  2. 返回值传递
    • 主函数需 return 递归调用的结果,否则违反函数返回值声明;
    • 递归分支需 return 子递归的结果,否则递归结果无法层层回传(最易踩坑);
  3. 辅助函数设计 :对外接口保持和迭代版一致,通过辅助函数传递 left/right,兼顾易用性与递归逻辑。

四、常见错误总结

  1. 语法错误:nums.size 忘记加括号(size() 是 vector 成员函数);
  2. 逻辑错误:边界更新用 left + 1 替代 mid + 1
  3. 递归错误:缺失 return 传递递归结果;
  4. 溢出错误:直接用 (left + right) / 2 计算 mid。

五、总结

  1. 二分查找的核心是闭区间 + 中点对比 + 区间收缩,迭代与递归的核心逻辑完全一致;
  2. 迭代版注重效率,是工程实践的首选;递归版注重逻辑直观,适合理解算法本质;
  3. 无论哪种实现,mid 计算、边界更新、终止条件是三大核心,也是新手最易出错的点。
相关推荐
深邃-11 小时前
【数据结构与算法】-二叉树(2):实现顺序结构二叉树(堆的实现),向上调整算法,向下调整算法,堆排序,TOP-K问题
数据结构·算法·二叉树·排序算法·堆排序··top-k
We་ct14 小时前
LeetCode 5. 最长回文子串:DP + 中心扩展
前端·javascript·算法·leetcode·typescript
王老师青少年编程18 小时前
csp信奥赛C++高频考点专项训练之贪心算法 --【哈夫曼贪心】:合并果子
c++·算法·贪心·csp·信奥赛·哈夫曼贪心·合并果子
叼烟扛炮19 小时前
C++第二讲:类和对象(上)
数据结构·c++·算法·类和对象·struct·实例化
天疆说19 小时前
【哈密顿力学】深入解读航天器交会最优控制中的Hamilton函数
人工智能·算法·机器学习
wuweijianlove19 小时前
关于算法设计中的代价函数优化与约束求解的技术7
算法
leoufung20 小时前
LeetCode 149: Max Points on a Line - 解题思路详解
算法·leetcode·职场和发展
样例过了就是过了20 小时前
LeetCode热题100 最长公共子序列
c++·算法·leetcode·动态规划
HXDGCL20 小时前
矩形环形导轨:自动化循环线的核心运动单元解析
运维·算法·自动化
谭欣辰20 小时前
C++ 排列组合完整指南
开发语言·c++·算法