递归算法之二分搜索(Binary Search)详细解读

二分搜索(Binary Search)是一种高效的查找算法,适用于有序数组或列表。它通过逐步缩小查找范围来快速定位目标元素,时间复杂度为 O(log⁡n),远比线性搜索的 O(n) 要快。二分搜索的基本思想是每次将查找范围缩小一半,因此特别适合于处理大规模数据。

1. 二分搜索的基本思想

给定一个递增排序的数组,我们希望在其中查找某个目标元素。二分搜索的过程是:

  1. 取数组的中间元素,并与目标元素比较。
  2. 如果中间元素等于目标元素,则查找成功。
  3. 如果中间元素小于目标元素,则在右半部分继续查找。
  4. 如果中间元素大于目标元素,则在左半部分继续查找。
  5. 重复这个过程,直到找到目标元素或查找范围为空。

2. 二分搜索的步骤

假设我们有一个排序数组 arr,目标元素为 target。其查找过程可以描述如下:

  1. 初始化两个指针:low 指向数组的起始位置,high 指向数组的末尾位置。
  2. 计算中间索引 mid = low + (high - low) / 2
  3. 比较 arr[mid]target
    • 如果 arr[mid] == target,则找到目标,返回 mid
    • 如果 arr[mid] < target,则 target 只可能在右半部分,调整 low = mid + 1
    • 如果 arr[mid] > target,则 target 只可能在左半部分,调整 high = mid - 1
  4. low > high 时,表示数组中没有目标元素,查找失败。

3. 二分搜索的实现

3.1 迭代实现
public class BinarySearch {// 二分查找的迭代实现public static int binarySearch(int[] arr, int target) {int low = 0;int high = arr.length - 1;while (low <= high) {int mid = low + (high - low) / 2;  // 避免整数溢出if (arr[mid] == target) {return mid;  // 找到目标,返回索引} else if (arr[mid] < target) {low = mid + 1;  // 在右半部分查找} else {high = mid - 1;  // 在左半部分查找}}return -1;  // 没有找到目标元素}public static void main(String[] args) {int[] arr = {1, 3, 5, 7, 9, 11, 13};int target = 7;int result = binarySearch(arr, target);if (result != -1) {System.out.println("元素 " + target + " 在索引 " + result);} else {System.out.println("元素 " + target + " 不在数组中");}}
}
代码详解:
  1. 初始化lowhigh 分别指向数组的开头和末尾。
  2. 中间元素计算mid = low + (high - low) / 2 计算中间索引,防止溢出。
  3. 查找逻辑:根据中间元素与目标元素的比较结果,调整 lowhigh 的值,缩小查找范围。
  4. 返回结果:如果找到目标元素,返回其索引;如果遍历完仍未找到,返回 -1 表示查找失败。
3.2 递归实现
public class BinarySearchRecursive {// 二分查找的递归实现public static int binarySearch(int[] arr, int target, int low, int high) {if (low > high) {return -1;  // 查找失败}int mid = low + (high - low) / 2;  // 避免整数溢出if (arr[mid] == target) {return mid;  // 找到目标} else if (arr[mid] < target) {return binarySearch(arr, target, mid + 1, high);  // 在右半部分递归查找} else {return binarySearch(arr, target, low, mid - 1);  // 在左半部分递归查找}}public static void main(String[] args) {int[] arr = {1, 3, 5, 7, 9, 11, 13};int target = 7;int result = binarySearch(arr, target, 0, arr.length - 1);if (result != -1) {System.out.println("元素 " + target + " 在索引 " + result);} else {System.out.println("元素 " + target + " 不在数组中");}}
}
代码详解:
  1. 递归终止条件:当 low > high 时,说明查找范围为空,查找失败,返回 -1
  2. 递归查找:通过比较中间元素与目标元素,将问题规模减半递归处理。

4. 二分搜索的时间复杂度

二分搜索的时间复杂度为 O(\log n),因为每次查找都将问题规模减半。与线性搜索的 O(n) 相比,二分搜索效率更高,特别是在大规模数据中。

  • 时间复杂度:O(log⁡n)
  • 空间复杂度
    • 迭代版本的空间复杂度为 O(1),因为只需要常数空间存储索引。
    • 递归版本的空间复杂度为 O(log⁡n),因为递归调用会占用栈空间。

5. 二分搜索的应用

5.1 数组查找

二分搜索最常见的应用是从有序数组中查找元素。由于其时间复杂度为 O(log⁡n),特别适合在大规模数据中进行查找。

5.2 查找最小/最大满足条件的元素

二分搜索还可以用于查找某个条件下的最小或最大值。例如,在查找某个数值范围内满足某个条件的最大元素或最小元素时,二分搜索是一个高效的选择。

5.3 应用于算法优化

在很多算法问题中,二分搜索可以作为一个优化手段,例如在动态规划问题中寻找状态转移方程的最优值。

6. 二分搜索的变种

6.1 查找第一个大于或等于目标值的元素

除了精确查找目标值,二分搜索还可以用于查找第一个大于或等于目标值的元素。这在实际应用中也非常常见。

public static int lowerBound(int[] arr, int target) {int low = 0;int high = arr.length - 1;while (low <= high) {int mid = low + (high - low) / 2;if (arr[mid] >= target) {high = mid - 1;} else {low = mid + 1;}}return low;
}

解释:这个函数返回第一个大于或等于目标值 target 的索引。

6.2 查找最后一个小于或等于目标值的元素

类似的,可以使用二分搜索查找最后一个小于或等于目标值的元素。

public static int upperBound(int[] arr, int target) {int low = 0;int high = arr.length - 1;while (low <= high) {int mid = low + (high - low) / 2;if (arr[mid] > target) {high = mid - 1;} else {low = mid + 1;}}return high;
}

解释:这个函数返回最后一个小于或等于目标值 target 的索引。

7. 二分搜索的局限性

虽然二分搜索很高效,但它只能用于有序数组或列表。如果数据未排序,使用二分搜索的前提条件就不成立。此外,二分搜索在数据结构中具有良好的应用效果,但在链表等线性结构中应用并不高效,因为链表无法直接访问中间元素。

8. 总结

二分搜索是一种高效的查找算法,时间复杂度为 O(log⁡n),特别适用于有序数组或列表。在很多实际问题中,二分搜索不仅仅用于查找元素,还可以用于优化一些算法或解决一些复杂的条件查找问题。通过变种形式,二分搜索可以扩展到查找满足特定条件的第一个或最后一个元素。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/454456.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

R语言机器学习算法实战系列(九)决策树分类算法 (Decision Trees Classifier)

禁止商业或二改转载,仅供自学使用,侵权必究,如需截取部分内容请后台联系作者! 文章目录 介绍教程下载数据加载R包导入数据数据预处理数据描述数据切割调节参数构建模型模型的决策树预测测试数据评估模型模型准确性混淆矩阵模型评估指标ROC CurvePRC Curve特征的重要性保存模…

N9042B UXA 信号分析仪

N9042BUXA 信号分析仪 - 2Hz到50GHz - 使用 N9042B UXA X 系列信号分析仪和各种测量应用软件&#xff0c;可以测试 5G、卫星等应用中的毫米波&#xff08;mmWave&#xff09;创新设计的真实性能。 N9042B 具有是德科技信号分析仪中较大的分析带宽和较深的动态范围&#xff0c…

【云原生】Kubernetes部署Jenkins静动Slave

Kubernetes部署Jenkins静动Slave 文章目录 Kubernetes部署Jenkins静动Slave文档介绍资源列表基础环境一、Jenkins Kubernetes清单文件二、使用静态Slave2.1、安装Kubernetes插件2.2、添加Agent2.3、使用Slave 三、使用动态Slave3.1、添加凭据3.2、配置动态Slave3.3、配置Jenkin…

基于SpringBoot+Vue+uniapp微信小程序的澡堂预订的微信小程序的详细设计和实现

项目运行截图 技术框架 后端采用SpringBoot框架 Spring Boot 是一个用于快速开发基于 Spring 框架的应用程序的开源框架。它采用约定大于配置的理念&#xff0c;提供了一套默认的配置&#xff0c;让开发者可以更专注于业务逻辑而不是配置文件。Spring Boot 通过自动化配置和约…

【深度学习中的注意力机制6】11种主流注意力机制112个创新研究paper+代码——加性注意力(Additive Attention)

【深度学习中的注意力机制6】11种主流注意力机制112个创新研究paper代码——加性注意力&#xff08;Additive Attention&#xff09; 【深度学习中的注意力机制6】11种主流注意力机制112个创新研究paper代码——加性注意力&#xff08;Additive Attention&#xff09; 文章目录…

kubernetes(三)

k8s之持久化存储pv&pvc 存储资源管理 在基于k8s容器云平台上&#xff0c;对存储资源的使用需求通常包括以下几方面&#xff1a; 1.应用配置文件、密钥的管理&#xff1b; 2.应用的数据持久化存储&#xff1b; 3.在不同的应用间共享数据存储&#xff1b; k8s支持Volume类…

Spring MVC文件请求处理-MultipartResolver

Spring Boot中的MultipartResolver是一个用于解析multipart/form-data类型请求的策略接口&#xff0c;通常用于文件上传。 对应后端使用MultipartFile对象接收。 RequestMapping("/upload")public String uploadFile(MultipartFile file) throws IOException {Strin…

十一、数据库配置

一、Navicat配置 这个软件需要破解 密码是&#xff1a;123456&#xff1b; 新建连接》新建数据库 创建一个表 保存出现名字设置 双击打开 把id设置为自动递增 这里就相当于每一次向数据库添加一个语句&#xff0c;会自动增长id一次 二、数据库的增删改查 1、Vs 建一个控…

磁编码器的工作原理和特点

目录 概述 1 磁编码器的构造 1.1 霍尔元件 1.2 永磁体 1.3 永磁体和霍尔元件的配置 2 磁编码器的工作原理 2.1 原理介绍 2.2 电气信号转换成角度 2.3 旋转角度传感器IC 3 磁编码器的特点和主要应用 概述 本文主要介绍磁编码器的构造原理&#xff0c;工作特性和应用特…

C/C++函数调用约定:__cdecl、__stdcall、__fastcall和__thiscall

目录 1.引言 2.常见函数调用约定 2.1.__cdecl 2.2.__stdcall 2.3.__fastcall 2.4.__thiscall 3.几种调用约定比较 4.注意事项 1.引言 在C和C编程中&#xff0c;函数调用约定&#xff08;Calling Convention&#xff09;定义了函数如何接收参数、如何返回值以及由谁来清…

【小沐学Golang】基于Go语言搭建静态文件服务器

文章目录 1、简介2、安装2.1 安装版2.2 压缩版 3、基本操作3.1 go run3.2 go build3.3 go install3.4 go env3.5 go module 4、文件服务器4.1 filebrowser4.2 gohttpserver4.3 goFile 5、FAQ5.1 go.mod 为空5.2 超时 结语 1、简介 https://golang.google.cn/ Go语言诞生于2007…

word表格跨页后自动生成的顶部横线【去除方法】

Hello World! Its been a long time. 这一年重心放在了科研、做事、追寻新的经历上&#xff0c;事有正事、琐事、幸事、哀事&#xff0c;内心与认知成长了一些&#xff0c;思想成熟了几分&#xff0c;技艺也有若干收获。不管怎样&#xff0c;来打个卡吧&#xff0c;纪念一下&…

Web前端高级工程师培训:使用 Node.js 构建一个 Web 服务端程序(3)

11、HTTP 协议 11-1、协议的定义 HTTP 是一种能够获取如 HTML 这样的网络资源的 protocol(通讯协议)。它是在 Web 上进行数据交换的基础&#xff0c;是一种 client-server 协议&#xff0c;也就是说&#xff0c;请求通常是由像浏览器这样的接受方发起的。一个完整的Web文档通…

Tailwind Starter Kit 一款极简的前端快速启动模板

Tailwind Starter Kit 是基于TailwindCSS实现的一款开源的、使用简单的极简模板扩展。会用Tailwincss就可以快速入手使用。Tailwind Starter Kit 是免费开源的。它不会在原始的TailwindCSS框架中更改或添加任何CSS。它具有多个HTML元素&#xff0c;并附带了ReactJS、Vue和Angul…

Docker安装Mysql5.7,解决无法访问DockerHub问题

Docker安装Mysql5.7&#xff0c;解决无法访问DockerHub问题 简介 Docker Hub 无法访问&#xff0c;应用安装失败&#xff0c;镜像拉取超时的解决方案。 摘要 &#xff1a; 当 Docker Hub 无法访问时&#xff0c;可以通过配置国内镜像加速来解决应用安装失败和镜像拉取超时的…

使用爬虫爬取Python中文开发者社区基础教程的数据

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;开发者-曼亿点 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 曼亿点 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a…

微信小程序文本收起展开

这里写自定义目录标题 微信小程序文本收起展开常见问题的梯形背景框 微信小程序文本收起展开 参考 https://juejin.cn/post/6963904955262435336 <!-- 常见问题解答 --><view classcontentBottom><view classBottomFirst><text id0 data-id0 class&quo…

python + mitmproxy 爬手机app (1)

起因&#xff0c; 目的: 想爬手机上某鱼。 mitmproxy 简介: 一句话: mitmproxy 就是中间人攻击. (只不过&#xff0c; 你安装&#xff0c;就代表你愿意承担风险。)源码&#xff1a;https://github.com/mitmproxy/mitmproxy文档: https://mitmproxy.org/ 安装过程: 见聊天记…

eCAP超声波测距-ePWM电机调速

目录 eCAP超声波测距 整体框架 关键模块 实验效果 PWM电机调速 DRV8833基本介绍 整体框架 eCAP超声波测距 本实验所用的超声波HC-SR04模块如下图所示&#xff0c;左边为正面图&#xff0c;右边为反面图。 HC-SR04基本工作原理&#xff1a; &#xff08;1&#xff09;采…

spring源码中的,函数式接口,注解@FunctionalInterface

调用方 /org/springframework/beans/factory/support/AbstractBeanFactory.java:333sharedInstance getSingleton(beanName, () -> {try {return createBean(beanName, mbd, args);}catch (BeansException ex) {// Explicitly remove instance from singleton cache: It mi…