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

【算法】二分查找

目录

一、概念

二、思路

三、边界问题


一、概念

在一本书中查找某一页,我们总是倾向于先翻到整本书的中间,然后根据当前页数判断我们想要找的页在当前页的左半本中还是右半本中,接着继续翻到剩下半本书的中间......

这就是二分查找思想在现实中的应用,但为什么这种方法能够比较快的查找到我们想要的页数?这是因为书中的页数是有序的,通过当前页数与目标页数的比较,我们能够确保目标页在当前页的左侧还是右侧


二、思路

二分查找的时间复杂度为O(logN),但是只适用于在有二分性质的序列中进行查找

二分性质:即我们可以自定义一个性质,让区间的左半部分都不满足,右半部分都满足 

最朴素的场景:有序的数组

  • 以下面的有序数组为例,首先用l和r维护我们需要二分的区间

  • 取区间的中点,判断中点值与我们的目标的大小关系

注意,如果区间元素的个数是奇数,那么只有一个中点;但如果元素个数是偶数,那么就会存在两个中点,例如上面的5和7都是中点

此处我们只讨论比较特殊的情况,即有偶数个元素的情况

对于该情况,我们可以选择每次取区间的左中点或右中点

取左中点:

int mid = (l + r) / 2;
int mid = l + (r - l) / 2; //防溢出

如果采用上面(l + r) / 2的方式来取左中点,如果l和r的值过大则有数值溢出的风险,因此建议使用第二个的方式

取右中点:

int mid = (l + r + 1) / 2;
int mid = l + (r - l + 1) / 2; //防溢出

由于除法向下取整,因此如果元素个数为奇数,不论是以取左中点的方式还是取右中点的方式,我们都能够取到中点,例如:

下面以偶数个元素为例

  • 以取左中点为例,我们取左中点值5

  • 5比8小,且我们的数组是升序的,则要查找的目标在右半部分

  • 重复上述步骤

要理解二分查找的思路并不难,有难度的地方在于其边界问题的处理


三、边界问题

以取左中点为例,我们先来看正确的代码

int Binary_Search(int* a, int sz, int x) //假设数组升序
{int l = 0, r = sz - 1; //区间左右边界while(l < r){int mid = l + (r - l) / 2; //取左中点if(a[mid] > x) //中点值比x大:目标在左半部分r = mid;else if(a[mid] < x) //中点值比x小:目标在右半部分l = mid + 1; else //相等return mid; //返回下标}//走出循环,说明l==r,判断此时位置是否与x相等if(a[l] == x)return l;return -1;
}

可以看到,当中点值比x大时,目标在左半部分,r移动到原来mid的位置;但当中点值比x小时,目标在右半部分,而l却移动到了mid+1的位置。为什么不是和r一样移动到mid?

我们看一个最简单的例子

只有两个元素,中点mid与l位置重合,且目标为2大于中点值1,此时l需要移动到mid+1的位置

可以正常找到我们的目标

但如果上一步中,l移动到mid的位置会怎么样呢?l和mid的位置本来就是重合的,移动过后位置没有改变,导致死循环

这说明,不论是取左中点还是右中点,一旦边界问题没有处理好,那么就会导致死循环

取右中点的代码:

int Binary_Search(int* a, int sz, int x) //假设数组升序
{int l = 0, r = sz - 1; //区间左右边界while(l < r){int mid = l + (r - l + 1) / 2; //取右中点if(a[mid] > x) //中点值比x大:目标在左半部分r = mid - 1;else if(a[mid] < x) //中点值比x小:目标在右半部分l = mid; else //相等return mid; //返回下标}//走出循环,说明l==r,判断此时位置是否与x相等if(a[l] == x)return l;return -1;
}

修改对应取中点的方式,并修改r和l的移动方式即可,原理和上面是相同的

如果不想考虑边界情况,则还有一种方式:

int Binary_Search(int* a, int sz, int x) //假设数组升序
{int l = 0, r = sz - 1; //区间左右边界while(l <= r){int mid = l + (r - l) / 2; //取左中点//int mid = l + (r - l + 1) / 2; //取右中点if(a[mid] > x) //中点值比x大:目标在左半部分r = mid - 1;else if(a[mid] < x) //中点值比x小:目标在右半部分l = mid + 1; else //相等return mid; //返回下标}return -1;
}

在这种方式下,r和l移动后都不会与原来的mid位置重合

完.

相关文章:

【算法】二分查找

目录 一、概念 二、思路 三、边界问题 一、概念 在一本书中查找某一页&#xff0c;我们总是倾向于先翻到整本书的中间&#xff0c;然后根据当前页数判断我们想要找的页在当前页的左半本中还是右半本中&#xff0c;接着继续翻到剩下半本书的中间...... 这就是二分查找思想在…...

第十五章 Vue工程化开发及Vue CLI脚手架

目录 一、引言 二、Vue CLI 基本介绍 三、安装Vue CLI 3.1. 安装npm和yarn 3.2. 安装Vue CLI 3.3. 查看 Vue 版本 四、创建启动工程 4.1. 创建项目架子 4.2. 启动工程 五、脚手架目录文件介绍 六、核心文件讲解 6.1. index.html 6.2. main.js 6.3. App.vue 一、…...

【Grafana】Grafana 基础入门

Grafana 简介 什么是Grafana Grafana 是一跨平台的开源的可视化分析工具&#xff0c;是目前网络架构和应用分析中最流行的时序数据展示工具&#xff0c;主要用于大规模指标数据的可视化展示。 它是用Go语言开发&#xff0c;可以做数据监控和数据统计&#xff0c;带有告警功能…...

如何获取页面上所有input框

要获取页面上所有的<input>框&#xff0c;你可以使用JavaScript。这通常可以通过查询DOM&#xff08;文档对象模型&#xff09;来实现&#xff0c;有几种方法可以做到这一点&#xff0c;包括使用document.querySelectorAll、document.getElementsByTagName或document.get…...

0-ARM Linux驱动开发-字符设备

一、字符设备概述 Linux 系统中&#xff0c;设备被分为字符设备、块设备和网络设备等。字符设备以字节流的方式进行数据传输&#xff0c;数据的访问是按顺序的&#xff0c;一个字节一个字节地进行读取和写入操作&#xff0c;没有缓冲区。例如&#xff0c;终端&#xff08;/dev…...

使用 Faster Whisper 和 Gradio 实现实时语音转文字

随着人工智能技术的进步&#xff0c;语音识别已经成为最热门的研究领域之一。如何实现高效、准确的实时语音转文字功能&#xff0c;是许多开发者关注的重点。本文将介绍如何使用 Faster Whisper 和 Gradio 这两个强大工具&#xff0c;快速构建一个实时语音转文字应用。 Faster…...

redis v6.0.16 安装 基于Ubuntu 22.04

redis安装 基于Ubuntu 22.04 本文演示如何在ubuntu22.04下&#xff0c;安装redis v6.0.16&#xff0c;并配置测试远程访问。 Step1 更新环境 sudo apt updateStep2 安装redis sudo apt install redis-server -yStep3 启动 sudo systemctl restart redissudo systemctl sta…...

Milvus - 内存索引类型详解

1. 背景概述 在大规模数据处理和向量相似性搜索场景中&#xff0c;内存索引的使用显著提升了查询速度和效率。Milvus 提供了多种内存索引类型&#xff0c;以满足不同场景下的性能需求。本文将介绍 Milvus 支持的各种内存索引类型及其适用场景、配置参数和使用方法。 2. 为什么…...

【STM32】按键控制LED 光敏传感器控制蜂鸣器

文章目录 前置知识按键介绍传感器模块硬件电路按键硬件电路传感器模块硬件电路 C语言数据类型在Keil中的对应写法C语言枚举 按键控制LED接线图Hardware文件夹&#xff08;模块化编程&#xff09;LED驱动程序封装Key(按键)驱动程序封装 main.c源文件 光敏传感器控制蜂鸣器接线图…...

flutter-防抖

在Flutter中实现输入框的防抖功能&#xff0c;通常是为了减少用户输入时触发的事件数量&#xff0c;特别是在进行网络请求时。防抖&#xff08;Debounce&#xff09;意味着在用户停止输入一段时间后才触发事件。以下是实现输入框防抖的一种方法&#xff1a; 1、使用Debounce类…...

什么是贪心算法

贪心算法&#xff08;Greedy Algorithm&#xff09;是一种逐步构建解决方案的方法&#xff0c;在每一步选择中都作出局部最优的选择&#xff0c;希望最终能够获得全局最优解。贪心算法的核心思想是贪心选择性质&#xff0c;即每次选择当前看来最好的解&#xff0c;不考虑未来可…...

YOLOv6-4.0部分代码阅读笔记-effidehead_lite.py

effidehead_lite.py yolov6\models\heads\effidehead_lite.py 目录 effidehead_lite.py 1.所需的库和模块 2.class Detect(nn.Module): 3.def build_effidehead_layer(channels_list, num_anchors, num_classes, num_layers): 1.所需的库和模块 import torch import t…...

重学SpringBoot3-整合 Elasticsearch 8.x (一)客户端方式

更多SpringBoot3内容请关注我的专栏&#xff1a;《SpringBoot3》 期待您的点赞&#x1f44d;收藏⭐评论✍ 这里写目录标题 1. 为什么选择 Elasticsearch&#xff1f;2. Spring Boot 3 和 Elasticsearch 8.x 的集成概述2.1 准备工作2.2 添加依赖 3. Elasticsearch 客户端配置方式…...

极简实现酷炫动效:Flutter隐式动画指南第三篇自定义Flutter隐式动画

目录 前言 一、TweenAnimationBuilder 二、使用TweenAnimationBuilder实现的一些动画效果 1.调整透明度的动画 2.稍微复杂点的组合动画 3.数字跳动的动画效果 前言 上两节博客分别介绍了Flutter中的隐式动画的基础知识以及使用隐式动画实现的一些动画效果。当系统提供的隐…...

无人机维护保养、部件修理更换技术详解

无人机作为一种精密的航空设备&#xff0c;其维护保养和部件修理更换是确保飞行安全、延长使用寿命的重要环节。以下是对无人机维护保养、部件修理更换技术的详细解析&#xff1a; 一、无人机维护保养技术 1. 基础构造理解&#xff1a; 熟悉无人机的基本构造&#xff0c;包括…...

xilinx vitis 更换硬件平台——ZYNQ学习笔记5

1、重新生成硬件信息 2、选择带有bit信息 3、设施路径和名字 4、打开更新硬件选项 5、选择新的硬件信息 6、打开系统工程界面 7、复位硬件信息 更新完毕...

vscode makfile编译c程序

编译工具安装 为了在 Windows 上安装 GCC&#xff0c;您需要安装 MinGW-w64。 MinGW-w64 是一个开源项目&#xff0c;它为 Windows 系统提供了一个完整的 GCC 工具链&#xff0c;支持编译生成 32 位和 64 位的 Windows 应用程序。 1. 下载MinGW-w64源代码&#xff0c;如图点…...

【学术论文投稿】探索嵌入式硬件设计:揭秘智能设备的心脏

【IEEE出版】第六届国际科技创新学术交流大会暨通信、信息系统与软件工程学术会议&#xff08;CISSE 2024&#xff09;_艾思科蓝_学术一站式服务平台 更多学术会议论文投稿请看&#xff1a;https://ais.cn/u/nuyAF3 目录 引言 嵌入式系统简介 嵌入式硬件设计的组成部分 设…...

JavaScript 概述

### JavaScript 概述 JavaScript 是一种广泛使用的编程语言&#xff0c;它最初由 Netscape 公司的 Brendan Eich 在1995年创建&#xff0c;目的是为网页添加交互性。随着时间的发展&#xff0c;JavaScript 已经从一个简单的脚本语言演变成了一种功能强大的编程语言&#xff0c;…...

2024年10月个人工作生活总结

本文为 2024年10月工作生活总结。 研发编码 一个证书过期问题记录 某天&#xff0c;现场反馈某服务无法使用问题&#xff0c;经同事排查&#xff0c;是因为服务证书过期导致的。原来&#xff0c;证书的有效期设置为5年&#xff0c;这个月刚好到期。 虽然这个问题与自己无直接…...

uniapp ,微信小程序,滚动(下滑,上拉)到底部加载下一页内容

前言 小程序的内容基本都是滑动到底部加载下一页&#xff0c;这个一般都没有什么好用的组件来用&#xff0c;我看vant和uniapp的插件里最多只有个分页&#xff0c;没有滚动到底部加载下一页。再次做个记录。 效果预览 下滑到底部若是有下一页&#xff0c;则会自动加载下一页&…...

MySQL中的日志类型有哪些?binlog、redolog和undolog的作用和区别是什么?

简介&#xff1a; MySQL中有六种日志文件&#xff0c;分别是&#xff1a;重做日志&#xff08;redo log&#xff09;、回滚日志&#xff08;undo log&#xff09;、二进制日志&#xff08;binlog&#xff09;、错误日志&#xff08;errorlog&#xff09;、慢查询日志&#xff0…...

【uni-app】创建自定义模板

1. 步骤 打开自定义模板文件夹 在此文件夹下创建模板文件&#xff08;注意后缀名&#xff09; 重新点击“新建页面” 即可看到新建的模板 2. 注意事项 创建的模板必须文件类型对应&#xff08;vue模板就创建*.vue文件, uvue模板就创建*.uvue文件&#xff09;...

Cesium移动Primitive位置

与传统的Entity实体不同&#xff0c;Primitive作为一种自定义基本图元&#xff0c;几何形状、材质和其他属性均由使用者定义&#xff0c;在需要绘制大量静态几何图形的高效渲染场景中更为适用。 Primitive的移动涉及到矩阵变换&#xff0c;并不像Entity那样给它替换一个新的坐…...

安卓13默认连接wifi热点 android13默认连接wifi

总纲 android13 rom 开发总纲说明 文章目录 1.前言2.问题分析3.代码分析4.代码修改5.编译6.彩蛋1.前言 有时候我们需要让固件里面内置好,相关的wifi的ssid和密码,让固件起来就可以连接wifi,不用在手动操作。 2.问题分析 这个功能,使用普通的安卓代码就可以实现了。 3.代…...

parted 磁盘分区

目录 磁盘格式磁盘分区文件系统挂载使用扩展 - parted、fdisk、gdisk 区别 磁盘格式 parted /dev/vdcmklabel gpt # 设置磁盘格式为GPT p # 打印磁盘信息此时磁盘格式设置完成&#xff01; 磁盘分区 开始分区&#xff1a; mkpart data_mysql # 分区名&…...

第三百零八节 Log4j教程 - Log4j日志到数据库

Log4j教程 - Log4j日志到数据库 我们可以使用log4j API通过使用org.apache.log4j.jdbc.JDBCAppender对象将信息记录到数据库中。 下表列出了JDBCAppender的配置属性。 属性描述bufferSize设置缓冲区大小。默认大小为1。driverJDBC驱动程序类。默认为sun.jdbc.odbc.JdbcOdbcDr…...

ai智能语音电销机器人可以做哪些事情?

AI智能语音电销机器人是结合人工智能技术进行自动化电话销售和客户互动的工具&#xff0c;能够完成一系列任务&#xff0c;有助于提升销售效果、优化客户体验和提高工作效率。以下是AI智能语音电销机器人可以做的一些主要事情&#xff1a; 1. 自动拨号 AI语音电销机器人可以自…...

CleanShot X - Mac(苹果电脑)专业截图录屏软件

CleanShot X 不仅提供了基础的截图功能&#xff0c;更内置了强大的图片编辑器&#xff0c;让你能轻松添加标注、形状、文本……以及将多个截图进行合并。 无论是为社交媒体制作图文&#xff0c;还是制作专业的产品 / 教程演示&#xff0c;CleanShot X 都能满足你的需求。 软件…...

Kafka 客户端工具使用分享【offsetexplorer】

前言&#xff1a; 前面我们使用 Spring Boot 继承 Kafka 完成了消息发送&#xff0c;有朋友会问 Kafka 有没有好用的客户端工具&#xff0c;RabbitMQ、RocketMQ 都有自己的管理端&#xff0c;那 Kafka 如何去查看发送出去的消息呢&#xff1f; 本篇我们就来分享一个好用的工具…...