二分查找算法介绍(边界值、循环条件、值的变化、二分查找的原理、异常处理)

一、二分查找法原理介绍

        二分查找是经典的查找算法之一,其原理也非常简单。

        对于已排序的数组(假设是整型,如果非整型,如果有排序和大小比较的定义,也可以使用二分查找),我们每次判断中间值与目标值的大小,从而排除另外半边。

       如下图所示,我们每次可以排除现有数组的一半及以上数据,也就是说,二分查找,利用了排除的原理。

二、二分查找的3个关键数据

        left:确定左边界,比如上图原数据的0。

        right:确定右边界,比如上图原数据的8。(有些题解,会用9表示,则right仍是右边界,只是此边界无法取到)

        middle:从中间开始判断,每次排除左边或右边的所有数据。

三、left、right的取值条件

        在此先说明一个重点

        left、right是限定数组的,每一次排除元素,都要保证得到的新数组,没有重复、缺失。【缺失可能出错,重复会导致复杂情况】

        缺失的情况其实一般不会出现。

        我们疑虑的,主要是这个问题:

        当 middle > 目标值时, 排除右边区域,那么:

        right = middle,还是

        right = middle - 1呢?

        如果用 right = middle,因为有重复数据,会不会更加保险呢?

        别急,接着往下看。

四、二分查找边界值处理【关键是,仅1个元素的数组】

        抽象left、right的选值,因为这并非重点,如果明白边界值处理,就能理解left、right选值和while循环条件的原理。

        第一,空数组【】

        假设我们有一个空数组,必定无所需元素,所以直接返回null。

        第二,1元素数组【a】

        假设数组中,只有一个元素a,此时只要判断a==目标值否,就能知道数组中是否有值。

        第三,其它情况。

        我们已知left、right是限定数组的,那么,如果目前数组的中心值middle,刚好等于目标值,就能返回答案。【这是最简单的情况,而且不用考虑1、2情况】

        但是常常会出现的问题是:

        1.数组中没有目标值。

        2.很可能一直迭代到left==right,或者left+1=right时,才得到目标值。【而第2个情况,又得从while条件里,找正确与否。】

                不考虑 left+2 == right ,或者 left+3 == right 的原因

        left+2 == right:中间值middle,可以等于

        ( left + right ) / 2                      比如【1,4,6】

       无论排除左边,还是右边,最后都剩下1元素数组【1】或者【6】

        left+3 == right : 中间值middle,为

        left+1【(left+left+3)除以2,化简】  比如【1, 4, 6, 9】

        那么,左边排除后,剩下【6,9】,即新问题【 left+1 == right 】的解决。

        右边排除后,剩下【1】,即为单元素问题。

        我们忽略第1个问题,因为如果解决了第2个问题,第1个问题也是迎刃而解。

                考虑2种情况, left == right,和 left+1 == right

        正如“第二,1元素数组【a】”所说,只要判断中间值 middle == (left+right)/2 == left与目标值的关系,就能知道数组中有无目标值。

        我们统一一种算法【满足开头所说的重点】:

        1. middle大于目标值,则舍弃右边,所以   right = middle - 1;

        2. middle小于目标值,则舍弃左边,所以   left = middle + 1;

        3. middle = (left + right) /2;

        这种算法可行吗?

        显然,当 left 恰好为 right 时,middle正好等于 left,恰好可以判断。

        所以,在单元素中满足。

        对于 left +1 == right呢?

        假设我们刚进入这个数组,那么 middle = left 【 ( left+left+1 ) / 2 】

        那么,经过判断,要不就说明 middle > 目标值,数组中无目标值。

        要不就是, middle < 目标值,判断右边的最后1个元素。

        这一步结束后,结果即1元素数组【a】的解法(或者成功判断)

        所以,本题满足。

五、while的循环条件

        我们已经了解left、right的取值,最后的重点是,while条件该如何处理?

        其实一般都知道,left < right 时,一般都可以继续执行,可是 left == right 时,该怎么办呢?

        结合上面的思路,其实一下就能看出来,如果 left == right, 不就恰好是 1元素的数组吗?

        那用 left <= right 作为循环条件,会不会无限循环呢?

        不会,因为我们把middle也排除了,做到了无重复,所以这个问题不算复杂。

六、异常处理

        考虑异常。

        数组元素重复

        最经典的,就是每一次比较middle后,使:

        left = middle;

        right = middle;

        出现的两种情况:

        假设现在有 1元素数组【a】。

        middle、left、right都指向a,无论a比目标值大、小,只要不等于,那么left、right会永远指向a,陷入死循环。

        当然,也有的情况是 2元素数组【a,b】

        left指向a, right指向b,此时middle指向a。

        并且,a比目标值小。

        此时,left = middle。

        而middle又是 left+right的二分之一,恰好是left,又是死循环。

        解决:

        特地判断 left == right, 和 left+1 == right两种情况。【那么代码就不够简洁,反而复杂了。】

        循环条件异常:

        对于 left初值为0, right初值为len-1。

        如果条件是 left < right ,明显会缺失数据。【不再解释】

        如果right初值为len呢?

        这是常常出现的问题,此时我们可以发现,right指向空元素。

        为了保持数据结构的统一性,必须在接下来的更新里,使得right永远指向空元素【不一定是无值,但是要使 right 指向的区间,已经被排除过。】

        这时,在排除时,就可以:

        right = middle。

        那么循环条件也明显了,如果 left <= right,那么在最后,一定会出现面对 空集合 ,却一直判断的情况。【注:空集合是我们更新后,新数组为null, 而在原数组中,(left+right )/2指向的元素,仍然有值】

七、结语

        总之,一定要做好 数组 更新的一致性,做好了这个,就能解题了。

         我是蚊子码农,如有补充或者疑问,欢迎在评论区留言。个人的知识体系可能没有那么完善,希望各位多多指正,谢谢大家。

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

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

相关文章

基于JSP的母婴用品网站系统

你好呀&#xff0c;我是计算机学长猫哥&#xff01;如果有需求可以文末加我。 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;JSP技术 工具&#xff1a;IDEA/Eclipse、Navicat、Maven 系统展示 首页 管理员功能界面 用户功能界面 前台首页功能界面 …

JUC从实战到源码:悲观锁和乐观锁真正了解了吗

【JUC】- 多线程与锁的知识 &#x1f604;生命不息&#xff0c;写作不止 &#x1f525; 继续踏上学习之路&#xff0c;学之分享笔记 &#x1f44a; 总有一天我也能像各位大佬一样 &#x1f3c6; 博客首页 怒放吧德德 To记录领地 &#x1f31d;分享学习心得&#xff0c;欢迎指…

游戏找不到d3dcompiler43.dll怎么办,分享5种有效的解决方法

在计算机使用过程中&#xff0c;我们经常会遇到一些错误提示&#xff0c;其中之一就是找不到某个文件。其中&#xff0c;找不到d3dcompiler43.dll是一个常见的问题。这个问题通常出现在运行某些游戏或应用程序时&#xff0c;由于缺少了d3dcompiler43.dll文件&#xff0c;导致程…

mysql的锁(全局锁)

文章目录 mysql按照锁的粒度分类全局锁概念&#xff1a;全局锁使用场景&#xff1a;全局锁备份案例&#xff1a; mysql按照锁的粒度分类 全局锁 概念&#xff1a; 全局锁就是对整个数据库实例加锁。MySQL 提供了一个加全局读锁的方法&#xff0c;命令是: Flush tables with…

#招聘数据分析#2024年5月前程无忧招聘北上广深成渝对比情况

#招聘数据分析#2024年5月前程无忧招聘北上广深成渝对比情况 0、根据前程无忧不完全样本统计&#xff0c;北上广深成都重庆平均月工资从高到低依次为 北京15037元、上海14230元、深圳13230元、广州11125元、成都10614元、重庆10388。 1、成都招聘样本数全量36301个&#xff0c…

搭建gateway网关

1.创建springBoot项目 可以将Server URL换成start.aliyun.com 2.配置路由与跨域处理 路由&#xff1a; server:port: 10010 # 网关端口 spring:application:name: gateway # 服务名称cloud:nacos:server-addr: localhost:8848 # nacos地址gateway:routes: # 网关路由配置- i…

JavaScript解构赋值

一、数组解构 以上要么不好记忆&#xff0c;要么书写麻烦&#xff0c;此时可以使用解构赋值的方法让代码更简洁。 数组解构是将数组的单元值快速批量赋值给一系列变量的简洁语法。 基本语法&#xff1a; 1、赋值运算符左侧的[]用于批量声明变量&#xff0c;右侧数组的单元值将…

MyBatis的各种查询功能

1、查询&#xff1a; 查询的标签select必须设置属性resultType或resultMap&#xff0c;用于设置实体类和数据库表的映射关系 resultType&#xff1a;自动映射&#xff0c;用于属性名和表中字段名一致的情况 resultMap&#xff1a;自定义映射&#xff0c;用于一对多或多对一或…

网络协议二

一、套接字Socket 基于 TCP UDP 协议的 Socket 编程&#xff0c;在讲 TCP 和 UDP 协议的时候&#xff0c;我们分客户端和服务端&#xff0c;在写程序的时候&#xff0c;我们也同样这样分。 在网络层&#xff0c;Socket 函数需要指定到底是 IPv4 还是 IPv6&#xff0c;分别对应设…

部署专属网页版ChatGPT-Next-Web

背景 工作学习中经常使用chat-gpt, 需求是多端使用gpt问答&#xff0c;因此搭建一个网页版本方便多个平台使用。最后选择了 ChatGPT-Next-Web 部署说明 一键部署自己的web页面&#xff0c;因为是使用免费的vercel托管的&#xff0c;vercel节点在全球都有&#xff0c;理论上突…

HSC Mailinspector loader.php 任意文件读取漏洞复现(CVE-2024-34470)

0x01 产品简介 HSC Mailinspector是一款远程电子邮件检查工具&#xff0c;支持POP3/IMAP4协议。它允许用户远程扫描最新邮件&#xff0c;并进行浏览、垃圾邮件排除、编辑、删除等操作&#xff0c;无需实际登录邮箱。 0x02 漏洞概述 由于HSC Mailinspector /public/loader.ph…

linux,lseek,append用法

打开写的.c文件 内容为 代码 <sys/stat.h> #include <fcntl.h> #include<stdio.h> #include<unistd.h> #include<string.h>//off_t lseek(int fd, off_t offset, int whence); //int open(const char *pathname, int flags); //int open(const …

【c++入门】函数重载,引用,内联函数,auto

函数重载 函数重载概念 什么是函数重载&#xff1f; 函数重载&#xff1a;是函数的一种特殊情况&#xff0c;C允许在同一作用域中声明几个功能类似的同名函数&#xff0c;这些同名函数的形参列表(参数个数 或 类型 或 类型顺序)不同&#xff0c;常用来处理实现功能类似数据类…

基于鲲鹏服务器搭建简单的开源论坛系统(LAMP)实践分享

LAMPLinux apache mysql( mariadb) PHP 结合利用华为云弹性负载均衡ELB弹性伸缩AS服务 优点&#xff1a; 将访问流量自动分发到多台云服务器&#xff0c;扩展应用系统对外的服务能力&#xff0c;实现更高水平的应用容错&#xff1b; 根据不同的业务、访问需求和预设策略&…

Java编程常见问题汇总一

系列文章目录 文章目录 系列文章目录前言一、字符串连接误用二、错误的使用StringBuffer三、测试字符串相等性四、数字转换成字符串五、利用不可变对象(Immutable) 前言 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分…

mac电脑用谷歌浏览器对安卓手机H5页面进行inspect

1、mac上在谷歌浏览器上输入 chrome://inspect 并打开该页面。 2、连接安卓手机到Mac电脑&#xff1a;使用USB数据线将安卓手机连接到Mac电脑。 3、手机上打开要的h5页面 Webview下面选择要的页面&#xff0c;点击inspect&#xff0c;就能像谷歌浏览器页面打开下面的页面&#…

大模型时代的具身智能系列专题(七)

北大王鹤团队 王鹤&#xff0c;北京大学前沿计算研究中心助理教授&#xff0c;本科毕业于清华大学&#xff0c;博士毕业于斯坦福大学&#xff0c;师从美国三院院士Leonidas. J Guibas教授。他创立并领导了具身感知与交互实验室(EPIC Lab)&#xff0c;实验室立足三维视觉感知与…

矩阵连乘问题

#include<iostream> using namespace std; #define N 7 void MatrixChain(int p[N],int n,int m[N][N],int s[N][N]) {for(int i1;i<n;i)m[i][i]0;for(int r2;r<n;r)//有多少个相乘(规模){for(int i1;i<n-r1;i){int jir-1;m[i][j]m[i][i]m[i1][j]p[i]*p[i1]*p[j…

【AREngine BUG 解决方法】无法获取有效的相机图像尺寸

近期拿了一台 华为mate20 Pro的手机&#xff0c;在运行AR示例的过程中出现了黑屏。 问题排查 SDK版本&#xff1a;com.huawei.hms:arenginesdk:3.7.0.3 定位 经排查&#xff0c;发现(ARCamera对象的相机内参) getImageDimensions()返回的图像尺寸的width和height都为0。 这…

Vue——初识组件

文章目录 前言页面的构成何为组件编写组件组件嵌套注册 效果展示 前言 在官方文档中&#xff0c;对组件的知识点做了一个很全面的说明。本篇博客主要写一个自己的案例讲解。 vue 官方文档 组件基础 页面的构成 说到组件之前&#xff0c;先大致说明下vue中页面的构成要素。 在…