当前位置: 首页 > news >正文

二分查找

二分查找

二分法(Binary Search)是一种高效的有序数据集查找算法,核心思想是 “通过不断将查找范围减半,快速缩小目标位置”,其时间复杂度为 O(log n)(n 为数据集长度),远优于线性查找的 O (n)。但需注意:二分法的前提是数据集已按升序或降序排列(通常默认升序)。

使用场景特点

  1. 搜索空间有序:无论是数组元素、函数输入、解的范围,其 “排序性” 是二分的基础;
  2. 判断可缩小空间:能通过一次简单判断(如 “中间值与目标的大小”“解是否可行”)将搜索空间直接减半。

实际应用问题场景

  1. 有序数据结构中的 “查找问题”
    • 判断有序数组中是否存在某个目标值,若存在则返回索引
    • 定位目标值的第一个出现位置最后一个出现位置(如去重、统计元素个数)。
    • 查找目标值的前驱(小于目标的最大元素)、后继(大于目标的最小元素)
  2. “单调函数” 的求解问题
    • 求解 “函数零点”(方程求解)
  3. “有序解空间” 的资源优化问题
    • 比如查找与一个数相等的另一个数的基数

算法原理

二分法的本质是 “利用有序性排除无效范围”,具体逻辑如下:

  1. 确定范围:初始查找范围是整个有序数据集(左边界 left 指向第一个元素,右边界 right 指向最后一个元素)。
  2. 计算中点:找到当前范围的中间位置 mid,取 mid 处的元素与目标值 target 比较。
  3. 缩小范围
    • mid 处元素 等于 target:找到目标,返回 mid(或记录结果)。
    • mid 处元素 小于 target:目标在 mid右侧(因数组有序),将左边界 left 调整为 mid + 1(排除左半部分)。
    • mid 处元素 大于 target:目标在 mid左侧,将右边界 right 调整为 mid - 1(排除右半部分)。
  4. 循环终止:重复步骤 2-3,直到 left > right(说明范围为空,目标不存在)。

实现步骤

步骤 1:初始化边界指针

定义两个变量 leftright,分别表示当前查找范围的 “左边界” 和 “右边界”:

步骤 2:循环缩小查找范围(核心步骤)

循环条件:left <= right(当 left > right 时,范围为空,终止循环)。

  1. 计算中点索引 mid
  2. 比较 arr[mid]target

步骤 3:处理查找失败

若循环结束(left > right)仍未返回,说明目标值不在数组中,返回 -1(或其他约定的 “不存在” 标记)

通用模版

模版1

BinarySearch(int arr[], int target) {// 初始化边界指针int left = 0, right = arr.size() - 1;//循环缩小查找范围(核心步骤)while(left <= right) {int mid = left + (right - left)/2;//比较中间元素与目标值if (nums[mid] == target) {// 找到目标值,返回索引return mid;} else if (nums[mid] < target) {// 中间值小于目标值,收缩左边界(目标在右半部分)left = mid + 1;} else {// 中间值大于目标值,收缩右边界(目标在左半部分)right = mid - 1;}}// 循环结束仍未找到,返回-1(表示不存在)return -1;
}

模板 2:二分法(找左边界,含重复元素)

适用于有序数组中查找 “第一个≥目标值” 的元素索引(如找第一个大于等于 target 的位置,常用于插入排序定位、重复元素中找首次出现的位置)。

// 函数功能:在升序数组nums中,找第一个≥target的元素索引(左边界)
// 参数:nums-升序有序数组,target-待查找目标值
int binarySearch_LeftBound(const vector<int>& nums, int target) {// 1. 初始化:查找范围覆盖整个数组int left = 0;int right = nums.size() - 1;int result = nums.size();  // 初始化为数组长度(表示未找到时返回插入位置)// 2. 核心循环:缩小范围,定位左边界while (left <= right) {int mid = left + (right - left) / 2;if (nums[mid] >= target) {// 找到可能的左边界,继续向左缩小范围(找更靠左的≥target的元素)result = mid;          // 暂存当前mid为候选结果right = mid - 1;       // 右边界左移,探索左半区} else {// 当前mid值小于target,目标在右半区left = mid + 1;}}// 3. 结果处理:返回最终找到的左边界(或插入位置)return result;
}

模板 3:二分法(找右边界,含重复元素)

适用于有序数组中查找 “最后一个≤目标值” 的元素索引(如找最后一个小于等于 target 的位置,常用于重复元素中找末次出现的位置)。

// 函数功能:在升序数组nums中,找最后一个≤target的元素索引(右边界)
// 参数:nums-升序有序数组,target-待查找目标值
int binarySearch_RightBound(const vector<int>& nums, int target) {// 1. 初始化:查找范围覆盖整个数组int left = 0;int right = nums.size() - 1;int result = -1;  // 初始化为-1(表示未找到时返回无效索引)// 2. 核心循环:缩小范围,定位右边界while (left <= right) {int mid = left + (right - left) / 2;if (nums[mid] <= target) {// 找到可能的右边界,继续向右缩小范围(找更靠右的≤target的元素)result = mid;          // 暂存当前mid为候选结果left = mid + 1;        // 左边界右移,探索右半区} else {// 当前mid值大于target,目标在左半区right = mid - 1;}}// 3. 结果处理:返回最终找到的右边界(或-1表示无符合元素)return result;
}

不同情况的不同之处

  1. 找左边界(找第一个大于等于 target 的位置) :>= 找右边界(找第一个小于等于target的位置):<= ,找哪一边的边界,就向哪一边缩小范围

中位数选取的核心原则

mid 的计算方式(向下 / 向上取整)由边界收缩方向决定:

  • 当收缩方向为 向左right = mid - 1)时,用向下取整(默认方式),确保范围有效缩小。

mid = left + (right - left) / 2

  • 当收缩方向为 向右left = mid + 1)时,若 leftright 可能相邻(差 1),需用向上取整,避免 mid 始终等于 left 导致的死循环。

left + (right - left + 1) / 2

本质上,所有调整都是为了保证:每次迭代后,搜索范围的大小必须严格减小,最终能在有限步内结束循环。

若都考虑使用 int mid = left + (right - left) / 2; 则需要像

// 找到可能的右边界,继续向右缩小范围(找更靠右的≤target的元素) result = mid; // 暂存当前mid为候选结果 left = mid + 1; // 左边界右移,探索右半区

用result保存答案,用left = mid + 1 来防止陷入循环

实数二分

实数二分

while((left-right)>eps)
{int ans;mid = left + (right - left) / 2;if (check(mid)){right = mid;}   else left = mid;
}
http://www.agseo.cn/news/158/

相关文章:

  • postcss-px-to-viewport-8-plugin无法转换tailwindcss样式问题
  • html中的latex数据公式展示
  • IK Multimedia TONEX MAX 1.10.2 逼真音色建模
  • 重塑云上 AI 应用“运行时”,函数计算进化之路
  • 82、SpringMVC 参数传递,浏览器和服务器之间的数据传输
  • 问卷调查数据库设计
  • Linux 系统调用详解与工作机制
  • 一客一策:Data Agent 如何重构大模型时代的智能营销?
  • MySQL函数
  • The 2025 Sichuan Provincial Collegiate Programming Contest
  • 详细介绍:Android 热点开发的相关api总结
  • 工业主板:工业自动化与智能设备的强大心脏
  • 十大经典排序算法 - lucky
  • 深度学习入门基于python
  • 2025网络赛1 C、D
  • 图像配准尝试
  • TypeScript索引访问类型详解
  • 【URP】Unity Shader Tags
  • 存储器的性能指标 计算机组成原理第三章
  • 基于Operator方式和二进制方式部署prometheus环境
  • 安全不是一个功能-而是一个地基
  • 你的错误处理一团糟-是时候修复它了-️
  • idea gitee 更新已取消 解决方案
  • 27家网省
  • 你的测试又慢又不可靠-因为你测错了东西
  • 国内人力资源信息管理软件排行:选红海云一体化人力HR系统
  • 历年 CSP-J/S 数学类真题知识点整理
  • Log4j2 CVE-2021-44228 漏洞复现
  • AI Compass前沿速览:字节Seedream4.0、Qwen3-Max、EmbeddingGemma、OneCAT多模态、rStar2-Agent
  • 使用DeepState进行API模糊测试的技术解析(第二部分)