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

一、二分查找的核心原理

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

  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 计算、边界更新、终止条件是三大核心,也是新手最易出错的点。
相关推荐
Billlly9 分钟前
ABC 453 个人题解
算法·题解·atcoder
玉树临风ives16 分钟前
atcoder ABC 452 题解
数据结构·算法
feifeigo12340 分钟前
基于马尔可夫随机场模型的SAR图像变化检测源码实现
算法
fengfuyao9851 小时前
基于STM32的4轴步进电机加减速控制工程源码(梯形加减速算法)
网络·stm32·算法
无敌昊哥战神2 小时前
深入理解 C 语言:巧妙利用“0地址”手写 offsetof 宏与内存对齐机制
c语言·数据结构·算法
小白菜又菜2 小时前
Leetcode 2075. Decode the Slanted Ciphertext
算法·leetcode·职场和发展
Proxy_ZZ03 小时前
用Matlab绘制BER曲线对比SPA与Min-Sum性能
人工智能·算法·机器学习
黎阳之光3 小时前
黎阳之光:以视频孪生领跑全球,赋能数字孪生水利智能监测新征程
大数据·人工智能·算法·安全·数字孪生
小李子呢02113 小时前
前端八股6---v-model双向绑定
前端·javascript·算法
XH华3 小时前
数据结构第九章:树的学习(下)
数据结构·学习