ImageVerifierCode 换一换
格式:DOCX , 页数:14 ,大小:21.35KB ,
资源ID:22308792      下载积分:3 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.bdocx.com/down/22308792.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(如何写出正确的二分查找Word格式.docx)为本站会员(b****7)主动上传,冰豆网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰豆网(发送邮件至service@bdocx.com或直接QQ联系客服),我们立即给予删除!

如何写出正确的二分查找Word格式.docx

1、这些都将在后文的各个算法说明中看到。知识准备结合算法导论和编程珠玑,下面说明循环不变式的概念与性质。循环不变式主要用来帮助理解算法的正确性。形式上很类似与数学归纳法,它是一个需要保证正确断言。对于循环不变式,必须证明它的三个性质:初始化:它在循环的第一轮迭代开始之前,应该是正确的。保持:如果在循环的某一次迭代开始之前它是正确的,那么,在下一次迭代开始之前,它也应该保持正确。终止:循环能够终止,并且可以得到期望的结果。文章说明(1)在推导每次数组减少的长度时,mid是不能代换成(left+right)/2的。这种形式代表了非整型的运算,没有舍去小数部分,而在代码中实际的mid是会舍去小数部分的。

2、(2)代码部分的=和=意义同C语言;文字说明部分的=代表赋值,=代表等式推导或者逻辑判断,由上下文而定。(3)除了3和5外,最初的各个变体代码参考于:二分查找,你真的会吗?为了符合思路的前后连贯和说明循环不变式,做了一些修改。原文的测试很方便,读者可以自行参考。(4)根据getgoing的提示和对原始参考代码的回顾,mid = (left+right)/2本身可能导致溢出,比较保险的写法是mid = left + (right-left)/2,如果想通过移位而不是除法提升速度,可以写成mid = left + (right-left)1)。 本文最初版本没有注意到这一点,现在已经修改,这个表达

3、式和最初的比不是很直观,专门在这里说明。当然,在理论推导而不是程序运行时是不必考虑溢出的,mid = (left+right)/2和mid = left + (right-left)/2总是相等,因此(1)和全文中的推导并未对此修改。1.二分查找值为key的下标,如果不存在返回-1。循环不变式:如果key存在于原始数组0,n-1,那么它一定在left,right中。第一轮循环开始之前,处理的数组就是原始数组,这时显然成立。每次循环开始前,key存在于待处理数组arrayleft, ., right中。对于arraymidkey,arraymid, ., right均大于key,key只可能存在

4、于arrayleft,mid-1中;对于arraymid=key,查找到了key对应的下标,直接返回。在前两种情况中,数组长度每次至少减少1(实际减少的长度分别是mid-left+1和right-mid+1),直到由1(left=right)变为0(leftright),不会发生死循环。结束时,leftright,待处理数组为空,表示key不存在于所有步骤的待处理数组,再结合每一步排除的部分数组中也不可能有key,因此key不存在于原数组。cppview plaincopy1. intbinsearch(int*array,intlength,key)2. 3. if(!array)4. re

5、turn-1;5. left=0,rightlength,mid;6. while(leftright)7. 8. mid+(right-left)/2;9. if(arraymid10. 11. 1;12. else13. 14. -15. 16. mid;17. 18. 19. 2.二分查找返回key(可能有重复)第一次出现的下标x,如果不存在返回-1如果key存在于数组,那么key第一次出现的下标x一定在left,right中,且有arrayleft=key。第一轮循环开始之前,处理的数组是0,n-1,这时显然成立。每次循环开始前,如果key存在于原数组,那么x存在于待处理数组array

6、left, ., right中。key,arrayleft, ., mid均小于key,x只可能存在于arraymid+1, ., right中。数组减少的长度为mid-left+1,至少为1。否则,arraymid=key, arraymid是arraymid, ., right中第一个大于等于key的元素,后续的等于key的元素(如果有)不可能对应于下标x,舍去。此时x在left, ., mid之中。数组减少的长度为right-(mid+1)+1,即right-mid,根据while的条件,当right=mid时为0。此时right=left,循环结束。此时left=right。在每次循环

7、结束时,left总是x的第一个可能下标,arrayright总是第一个等于key或者大于key的元素。那么对应于left=right的情况,检查arrayleft即可获得key是否存在,若存在则下标为x;对于leftright的情况,其实是不用考虑的。因为left=上一次循环的mid+1,而midright,意味着mid = right,但此时必有left = right,这一轮循环从开始就不可能进入。binsearch_first(intlength,intlength-1,mid;mid+1;11. elseif(arrayleft=left;17. 3.二分查找返回key(可能有重复)最

8、后一次出现的下标x,如果不存在返回-1(模仿2的第一版)如果key存在于数组,那么key最后一次出现的下标x一定在left,right中,且有arrayleft对于arraymid=key, arraymid是arrayleft, ., mid中最后一个值为key的元素,那么x的候选只能在arraymid, . ,right中,数组减少长度为mid-left。除非left = right或left = right-1,否则数组长度至少减小1。由于while的条件,只有后一种情况可能发生,如果不进行干预会陷入死循环,加入判断分支即可解决。key, arraymid, ., right均大于key

9、,x只可能在left, ., mid-1之中。数组减少的长度为(right-mid)+1,同样至少为1。=right,right总是从数组末尾向开始的倒序中第一个候选的x,检查它的值是否符合要求即可。而left总是上一轮删掉失去x资格的元素后的第一个元素,不过这里用不到。说明:与上一种不同,这个算法不能简单地根据对称,从上一个算法直接改过来,由于整数除法总是舍弃小数,mid有时会离left更近一些。所以这种算法只是沿着上一个算法思路的改进,看上去并不是很漂亮。binsearch_last(intif(leftmid)if(arrayrightright;19. 20. 21. 22. 23.

10、24. 25. 26. 4.二分查找返回key(可能有重复)最后一次出现的下标x,如果不存在返回-1(修改版)根据3中的讨论,可以发现不能直接照搬的原因是mid=(left+right)/2的舍弃小数,在left+1=right且arrayleft=key时,如果不加以人为干预会导致死循环。既然最终需要干预,干脆把需要干预的时机设置为终止条件就行了。使用while(leftright-1)可以保证每次循环时数组长度都会至少减一,终止时数组长度可能为2(left+1=right)、1(left=mid,上一次循环时right取mid=left),但是不可能为0。(每一次循环前总有left=mid

11、right)。同3一样,right总是指向数组中候选的最后一个可能为key的下标,此时只需先检查right后检查left是否为key就能确定x的位置。这样就说明了循环不变式的保持和终止,就不再形式化地写下来了。对于两种情况的合并:arraymid = key时,mid有可能是x,不能将其排除;arraymid=left,违反则意味着x不存在。写下arraymid的比较判断分支:(1) arraymidkey, 意味着x只可能在arraymid, ., right之间,下一次循环令left = mid,数组长度减少了(mid-1)-left+1 = mid-left,这个长度减少量只有在righ

12、t-left=key,意味着x只可能在arrayleft ,. ,mid-1之间,下一次循环令right = mid-1,同样推导出数组长度至少减少了1。这样,把循环条件缩小为rightleft+1,和4一样,保证了(1)中每次循环必然使数组长度减少,而且终止时也和4的情况类似:终止时待处理数组长度只能为2或1或者空(left接着保持中的讨论,结束时,符合的x要么在最终的数组中,要么既不在最终的数组中也不在原始的数组中(因为每一次循环都是剔除不符合要求的下标)。数组长度为2时,right=left+1,此时先检查right后检查left。如果都不符合其值小于key,那么返回-1。数组长度为1时

13、,只用检查一次;数组长度为0时,这两个都是无效的,检查时仍然不符合条件。把这三种情况综合起来,可以写出通用的检查代码。反过来,根据精简的代码来理解这三种情况比正向地先给出直观方法再精简要难一些。binsearch_last_less(int1)7.二分查找返回刚好大于key的元素下标x,如果不存在返回-1和6很类似,但如果只是修改循环中下标的改变而不修改循环条件是不合适的,下面仍要进行严谨的说明和修正。如果原始数组中存在比key大的元素,那么原始数组中符合要求的元素对应下标x存在于待处理的数组。仍然先把执行while循环的条件暂时写为right=key, 意味着x只可能在arraymid+1,

14、 ., right之间,下一次循环令left = mid,数组长度减少了mid-left+1,减少量至少为1。key,意味着x只可能在arrayleft ,. ,mid之间,下一次循环令right = mid,数组长度减少了right-(mid+1)+1= right-mid,只有在right=mid时为0,此时left=right=mid。因此,循环条件必须由right=left收缩为rightleft才能避免left=right时前者会进入的死循环。由循环的终止条件,此时left类似2的分析,leftright是不可能的,只有left=right。此时检查arrayrightkey成立否就

15、可以下结论了,它是唯一的候选元素。补充说明:如果是对数组进行动态维护,返回值-1可以改为length+1,表示下一个需要填入元素的位置。binsearch_first_more(int8.总结:如何写出正确的二分查找代码?结合以上各个算法,可以找出根据需要写二分查找的规律和具体步骤,比死记硬背要强不少,万变不离其宗嘛:(1)大体框架必然是二分,那么循环的key与arraymid的比较必不可少,这是基本框架;(2)循环的条件可以先写一个粗略的,比如原始的while(left=right)就行,这个循环条件在后面可能需要修改;(3)确定每次二分的过程,要保证所求的元素必然不在被排除的元素中,换句话说,所求的元素要么在保留的其余元素中,要么可能从一开始就不存在于原始的元素中;(4)检查每次排除是否会导致保留的候选元素个数的减少?如果没有,分析这个边界条件,如果它能导致循环的结束,那么没有问题;否则,就会陷入死循环。为了避免死循环,需要修改循环条件,使这

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1