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

一、二分查找的核心原理

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

  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 计算、边界更新、终止条件是三大核心,也是新手最易出错的点。
相关推荐
Keven_111 分钟前
算法札记:二分
算法·二分
TCW11217 分钟前
AI底层系列:用C++实现线性代数的公式推导与算法设计-6.线性方程组的解集
c++·人工智能·算法
luoyayun3619 分钟前
从零实现 EBU R128 LUFS 响度分析:K-weighting 滤波、双门限算法
算法·lufs响度分析
小糯米60112 分钟前
JS 数组
数据结构·算法·排序算法
拳里剑气24 分钟前
C++算法:链表
c++·算法·链表
凌波粒29 分钟前
LeetCode--90.子集II(回溯算法)
数据结构·算法·leetcode
旖-旎35 分钟前
《LeetCode 417 太平洋大西洋水流问题 FloodFill DFS 解法》
c++·算法·深度优先·力扣·floodfill
凌波粒38 分钟前
LeetCode--46.全排列(回溯算法)
数据结构·算法·leetcode
2zcode1 小时前
项目文档:基于MATLAB语音信号变声算法设计与实现
算法·matlab·语音识别
指令集梦境1 小时前
图解:单调栈算法模板(Java语言)
java·开发语言·算法