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

本文主要是介绍二分查找算法介绍(边界值、循环条件、值的变化、二分查找的原理、异常处理),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一、二分查找法原理介绍

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

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

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

二、二分查找的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.chinasem.cn/article/1028513

相关文章

Python字符串处理方法超全攻略

《Python字符串处理方法超全攻略》字符串可以看作多个字符的按照先后顺序组合,相当于就是序列结构,意味着可以对它进行遍历、切片,:本文主要介绍Python字符串处理方法的相关资料,文中通过代码介... 目录一、基础知识:字符串的“不可变”特性与创建方式二、常用操作:80%场景的“万能工具箱”三、格式化方法

Spring Boot 处理带文件表单的方式汇总

《SpringBoot处理带文件表单的方式汇总》本文详细介绍了六种处理文件上传的方式,包括@RequestParam、@RequestPart、@ModelAttribute、@ModelAttr... 目录方式 1:@RequestParam接收文件后端代码前端代码特点方式 2:@RequestPart接

SpringBoot全局异常拦截与自定义错误页面实现过程解读

《SpringBoot全局异常拦截与自定义错误页面实现过程解读》本文介绍了SpringBoot中全局异常拦截与自定义错误页面的实现方法,包括异常的分类、SpringBoot默认异常处理机制、全局异常拦... 目录一、引言二、Spring Boot异常处理基础2.1 异常的分类2.2 Spring Boot默

SpringBoot的全局异常拦截实践过程

《SpringBoot的全局异常拦截实践过程》SpringBoot中使用@ControllerAdvice和@ExceptionHandler实现全局异常拦截,@RestControllerAdvic... 目录@RestControllerAdvice@ResponseStatus(...)@Except

MySQL 筛选条件放 ON后 vs 放 WHERE 后的区别解析

《MySQL筛选条件放ON后vs放WHERE后的区别解析》文章解释了在MySQL中,将筛选条件放在ON和WHERE中的区别,文章通过几个场景说明了ON和WHERE的区别,并总结了ON用于关... 今天我们来讲讲数据库筛选条件放 ON 后和放 WHERE 后的区别。ON 决定如何 "连接" 表,WHERE

Java线程池核心参数原理及使用指南

《Java线程池核心参数原理及使用指南》本文详细介绍了Java线程池的基本概念、核心类、核心参数、工作原理、常见类型以及最佳实践,通过理解每个参数的含义和工作原理,可以更好地配置线程池,提高系统性能,... 目录一、线程池概述1.1 什么是线程池1.2 线程池的优势二、线程池核心类三、ThreadPoolE

MybatisPlus中几种条件构造器运用方式

《MybatisPlus中几种条件构造器运用方式》QueryWrapper是Mybatis-Plus提供的一个用于构建SQL查询条件的工具类,提供了各种方法如eq、ne、gt、ge、lt、le、lik... 目录版本介绍QueryWrapperLambdaQueryWrapperUpdateWrapperL

Python+FFmpeg实现视频自动化处理的完整指南

《Python+FFmpeg实现视频自动化处理的完整指南》本文总结了一套在Python中使用subprocess.run调用FFmpeg进行视频自动化处理的解决方案,涵盖了跨平台硬件加速、中间素材处理... 目录一、 跨平台硬件加速:统一接口设计1. 核心映射逻辑2. python 实现代码二、 中间素材处

Spring Boot Interceptor的原理、配置、顺序控制及与Filter的关键区别对比分析

《SpringBootInterceptor的原理、配置、顺序控制及与Filter的关键区别对比分析》本文主要介绍了SpringBoot中的拦截器(Interceptor)及其与过滤器(Filt... 目录前言一、核心功能二、拦截器的实现2.1 定义自定义拦截器2.2 注册拦截器三、多拦截器的执行顺序四、过

Go异常处理、泛型和文件操作实例代码

《Go异常处理、泛型和文件操作实例代码》Go语言的异常处理机制与传统的面向对象语言(如Java、C#)所使用的try-catch结构有所不同,它采用了自己独特的设计理念和方法,:本文主要介绍Go异... 目录一:异常处理常见的异常处理向上抛中断程序恢复程序二:泛型泛型函数泛型结构体泛型切片泛型 map三:文