| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> 数据结构与算法 -> 【玩转二分查找Ⅰ】左闭右闭型,左开右闭型,左闭右开型(动图演绎) -> 正文阅读 |
|
[数据结构与算法]【玩转二分查找Ⅰ】左闭右闭型,左开右闭型,左闭右开型(动图演绎) |
目录 ?一、前言①什么是二分查找?????????二分查找是在有序表中查找目标元素的算法,其基本思想其实就是“猜数字游戏”——已知某个数k在0~1000之内,如何猜出这个数具体是多大呢?二分查找是这样处理的:
????????如此不断的压缩范围数据的范围,最后当只剩下1个数据时答案已经被锁定了(当然如果运气好,那我们选定的“折半值”可能就是k了),可以看到二分查找不断折半缩小待查找的数据范围因此二分查找也被翻译成“折半查找”。 ②二分查找有多优秀?????????试想如果我们从0~1000一一枚举,那我们最倒霉需要猜1000次,而使用二分的思路最坏也只?要需要10次(怎么算出来的呢?,而,所以10次就可以包含完0~1000的所有情况)。如果数据范围更大些,那效率的差距将会更加的突出。 假设检查一个元素需要1ms,那我们可以得到以下的表格: ? ? ? ? ?从这个实际问题中抽象出我们的算法,一一猜数对应着暴力枚举法,它的时间复杂度为,相比之下,?二分查找的时间复杂度为,所以是相当优秀漂亮的算法。 ③使用前提? ? ? ? 使用二分查找的前提是原数据是一个有序表,即具有单调性。所以说检索也是排序最重要的应用之一。 ④二分查找难吗?二分查找真的很简单吗?其实也并不简单。看看 Knuth 大佬(发明 KMP 算法的那位)怎么说的:
这句话可以这样理解:思路很简单,细节是魔鬼。 所以在这篇文章中向大家介绍二分查找的三种形式,虽然整体形式是极其相似的,但是略微的差别却带来了极大的不同。也相信学习完这篇博客大家可以熟练运用这三种形式的二分查找。 二、左闭右闭型①代码模板左闭右闭型是最典型的模板,也是我们学习的基础,我们依然从猜数字的角度来理解:
分析:
看不懂?没关系,用下面的四张动图来帮你理解。 ②动图演示(1)检索 target = 29 是否存在 更加直观的,我们将数据数据对应到二叉树中 【如何构建的呢】 ?其实就是我们对猜数字游戏的模拟,举个🌰:
【特性】
(2)检索 target = 29 是否存在 ?(3)target 找不到的情况(搜索 target = 35) ??【和情况(2)有什么区别呢】
(4)更复杂点的情况(采用mid = ( left + right + 1) / 2) ③中间位置取法的区别以一组数据 [ 1, 2, 3, 4 , 5, 6 ]为🌰:
?[小细节] 如果left + right 存在溢出的问题,则上述中间位置的取法可以改成下面两种形式,保证不会溢出
④为什么称其为左闭右闭型? ? ? ? 因为左闭右闭型检索的区域在? [left , right]? 之间。同样的道理,左闭右开检索的区域在 [left, right), 左开右闭的检索区域在 (left, right] 三、左开右闭,左闭右开型①左闭右开,左开右闭,左闭右开的区分? ? ? 核心在于while判断语句中有没有等于号,以及中间值的取法。试想left 与 right不断接近时,最终left 与right紧挨: 1)?中间值取法为 (left + right) / 2 时
2)中间值取法为 (left + right + 1) / 2 时
四、寻找上下界二分查找除了可以用来检索一个数是否存在,还可以用来寻找上下界,来看看是怎样实现的吧!
?【分析】 1)为什么想到二分查找? ? ? ? ? 因为二分查找的本质是二段性,只要满足二段性的问题都可以转化为二分查找的问题。 2)如何理解二段性呢? ? ? ? ? 在猜数字游戏中,二段性体现在target左边的元素都比它小,target右边的元素都比它大,所以结合数据的单调性我们可以不断的压缩区间以定位到目标值。而在这个问题中仍然具有二段性,第一个发生错误的版本的之前版本的都是正确的,之后的都是错误的,由此我们仍然可以不断的压缩区间从而得到第一个发生错误的版本。 3)如何理解左开右闭型的代码? ? ? ? ? 若当前mid版本为正确,则 left 可以压缩到mid + 1,若当前版本正确,则将right压缩到mid。可以是mid - 1吗?不妨这样思考,如果当前mid正处于第一个发生错误的版本,right = mid - 1后不是彻底排除了正确答案了吗,永远也找不到了。 ?????????left 和 right 相遇之前,left不可能到达第一个错误版本,只会无限接近;right不可能超过第一个错误版本,只会到达第一个错误版本,所以最后 left 与 right 的关系是这样的。最终,?left = mid + 1使得 left 与 right重合也就锁定了第一个错误版本 。 4)如果上体的中间元素取法为 (left + right + 1) / 2会发生什么? ? ? ? ? 会陷入死循环!?因为 mid = right,mid是错误版本,因此执行语句"right = mid",也就意味着left 与 right的区间没有发生压缩。不断重复这个过程就陷入了死循环。 5)延伸:如果最后的结果是这样的呢? 此时我们的中间元素取法如果为(left + right ) / 2 ,则同样的我们会陷入死循环。 6)总结
用左闭右闭型的二分查找也可以实现上下界定位,并且好理解很多。来看看是怎么实现的:
【分析】与模板唯一的区别在于,找到了继续找。所以上述代码的作用是找到第一个比target小的位置(也就是要插入位置)。当然如果将if里的条件改成 " target >= nums[mid] ",那么相应的作用就变成找到第一个闭target大的位置,当然也可以作为插入位置。 给大家演示一下: nums[] = {1, 2, 2, 2, 2, 2, 2, 3 ,4 ,5} , target? = 2 的情况吧? ? ?五、巩固练习
代码上面都呈现过,一定要都尝试下。 |
|
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 | -2024/11/26 18:27:23- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |