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

一、二分查找的核心原理

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

  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 计算、边界更新、终止条件是三大核心,也是新手最易出错的点。
相关推荐
倒头就睡的小比特2 天前
算法竞赛C++常用的STL
c++·算法
小羊没烦恼!2 天前
初探性能优化——2个月到4小时的性能提升
java·开发语言·windows·算法·c#
猎头南楼3 天前
知识社区推荐系统实践:新用户冷启动与长短期兴趣建模的挑战 资深推荐算法工程师
人工智能·深度学习·算法·机器学习
m0_547486663 天前
《数据结构教程》全套 PPT课件2026
数据结构
旖旎夜光3 天前
力控面试题 01.01: 判定字符是否唯一(位运算) —— 题解
c++·学习·算法·leetcode·力控
wzdark3 天前
大规模并行计算中的负载均衡算法研究4
算法
Because_of_Her13 天前
并查集-听课笔记
笔记·算法·并查集
码流子3 天前
高速公路安全监测实践:碰撞监测预警+物联网底座,从感知到处置的闭环
大数据·人工智能·物联网·算法·架构
another heaven3 天前
【算法/C++ MD5算法能否逆解码?原理、C++实现与同类哈希算法对比】
c++·算法·哈希算法
wzdark3 天前
从算法设计模式看编程思维的抽象能力4
算法