首页 最新 热门 推荐

  • 首页
  • 最新
  • 热门
  • 推荐

程序员编程艺术第二十五章:Jon Bentley:90%无法正确实现二分查找

  • 25-03-02 16:01
  • 3075
  • 7910
blog.csdn.net

第二十五章:二分查找实现(Jon Bentley:90%程序员无法正确实现)

作者:July
出处:结构之法算法之道

引言

    Jon Bentley:90%以上的程序员无法正确无误的写出二分查找代码。也许很多人都早已听说过这句话,但我还是想引用《编程珠玑》上的如下几段文字: 

“二分查找可以解决(预排序数组的查找)问题:只要数组中包含T(即要查找的值),那么通过不断缩小包含T的范围,最终就可以找到它。一开始,范围覆盖整个数组。将数组的中间项与T进行比较,可以排除一半元素,范围缩小一半。就这样反复比较,反复缩小范围,最终就会在数组中找到T,或者确定原以为T所在的范围实际为空。对于包含N个元素的表,整个查找过程大约要经过log(2)N次比较。 
多数程序员都觉得只要理解了上面的描述,写出代码就不难了;但事实并非如此。如果你不认同这一点,最好的办法就是放下书本,自己动手写一写。试试吧。 
我在贝尔实验室和IBM的时候都出过这道考题。那些专业的程序员有几个小时的时间,可以用他们选择的语言把上面的描述写出来;写出高级伪代码也可以。考试结束后,差不多所有程序员都认为自己写出了正确的程序。于是,我们花了半个钟头来看他们编写的代码经过测试用例验证的结果。几次课,一百多人的结果相差无几:90%的程序员写的程序中有bug(我并不认为没有bug的代码就正确)。 
我很惊讶:在足够的时间内,只有大约10%的专业程序员可以把这个小程序写对。但写不对这个小程序的还不止这些人:高德纳在《计算机程序设计的艺术 第3卷 排序和查找》第6.2.1节的“历史与参考文献”部分指出,虽然早在1946年就有人将二分查找的方法公诸于世,但直到1962年才有人写出没有bug的二分查找程序。 ”——乔恩·本特利,《编程珠玑(第1版)》第35-36页。

    你能正确无误的写出二分查找代码么?不妨一试。

二分查找代码

     二分查找的原理想必不用多解释了,不过有一点必须提醒读者的是,二分查找是针对的排好序的数组。OK,纸上读来终觉浅,觉知此事要躬行。我先来写一份,下面是我写的一份二分查找的实现(之前去某一家公司面试也曾被叫当场实现二分查找,不过结果可能跟你一样,当时就未能完整无误写出),有任何问题或错误,恳请不吝指正:

  1. //二分查找V0.1实现版
  2. //copyright@2011 July
  3. //随时欢迎读者找bug,email:[email protected]。
  4. //首先要把握下面几个要点:
  5. //right=n-1 => while(left <= right) => right=middle-1;
  6. //right=n => while(left < right) => right=middle;
  7. //middle的计算不能写在while循环外,否则无法得到更新。
  8. int binary_search(int array[],int n,int value)
  9. {
  10. int left=0;
  11. int right=n-1;
  12. //如果这里是int right = n 的话,那么下面有两处地方需要修改,以保证一一对应:
  13. //1、下面循环的条件则是while(left < right)
  14. //2、循环内当array[middle]>value 的时候,right = mid
  15. while (left<=right) //循环条件,适时而变
  16. {
  17. int middle=left + ((right-left)>>1); //防止溢出,移位也更高效。同时,每次循环都需要更新。
  18. if (array[middle]>value)
  19. {
  20. right =middle-1; //right赋值,适时而变
  21. }
  22. else if(array[middle]
  23. {
  24. left=middle+1;
  25. }
  26. else
  27. return middle;
  28. //可能会有读者认为刚开始时就要判断相等,但毕竟数组中不相等的情况更多
  29. //如果每次循环都判断一下是否相等,将耗费时间
  30. }
  31. return -1;
  32. }
    简单测试下,运行结果如下所示(当然,一次测试正确不代表程序便0 bug了,且测试深度远远不够):

测试

    也许你之前已经把二分查找实现过很多次了,但现在不妨再次测试一下。关闭所有网页,窗口,打开记事本,或者编辑器,或者直接在本文评论下,不参考上面我写的或其他任何人的程序,给自己十分钟到N个小时不等的时间,立即编写一个二分查找程序。

    当然,能正确写出来不代表任何什么,不能正确写出来亦不代表什么,仅仅针对Jon Bentley的言论做一个简单的测试而已。下一章,请见第二十六章:基于给定的文档生成倒排索引的编码与实践。谢谢。

总结

    本文发表后,马上就有很多朋友自己尝试了。根据从朋友们在本文评论下留下的代码,发现出错率最高的在以下这么几个地方:

  1. 注释里已经说得很明白了,可还是会有不少朋友犯此类的错误:
    1. //首先要把握下面几个要点:    
    2. //right=n-1 => while(left <= right) => right=middle-1;    
    3. //right=n   => while(left <  right) => right=middle;    
    4. //middle的计算不能写在while循环外,否则无法得到更新。    
  2. 还有一个最最常犯的错误是@土豆:
    middle= (left+right)>>1; 这样的话left与right的值比较大的时候,其和可能溢出。
    各位继续努力。
    updated:各位,可以到此处0积分下载本blog最新博文集锦第6期CHM文件:http://download.csdn.net/detail/v_july_v/4020172。

文章知识点与官方知识档案匹配,可进一步学习相关知识
算法技能树首页概览49575 人正在系统学习中
注:本文转载自blog.csdn.net的v_JULY_v的文章"http://blog.csdn.net/v_july_v/article/details/7093204"。版权归原作者所有,此博客不拥有其著作权,亦不承担相应法律责任。如有侵权,请联系我们删除。
复制链接
复制链接
相关推荐
发表评论
登录后才能发表评论和回复 注册

/ 登录

评论记录:

未查询到任何数据!
回复评论:

分类栏目

后端 (14832) 前端 (14280) 移动开发 (3760) 编程语言 (3851) Java (3904) Python (3298) 人工智能 (10119) AIGC (2810) 大数据 (3499) 数据库 (3945) 数据结构与算法 (3757) 音视频 (2669) 云原生 (3145) 云平台 (2965) 前沿技术 (2993) 开源 (2160) 小程序 (2860) 运维 (2533) 服务器 (2698) 操作系统 (2325) 硬件开发 (2492) 嵌入式 (2955) 微软技术 (2769) 软件工程 (2056) 测试 (2865) 网络空间安全 (2948) 网络与通信 (2797) 用户体验设计 (2592) 学习和成长 (2593) 搜索 (2744) 开发工具 (7108) 游戏 (2829) HarmonyOS (2935) 区块链 (2782) 数学 (3112) 3C硬件 (2759) 资讯 (2909) Android (4709) iOS (1850) 代码人生 (3043) 阅读 (2841)

热门文章

101
推荐
关于我们 隐私政策 免责声明 联系我们
Copyright © 2020-2024 蚁人论坛 (iYenn.com) All Rights Reserved.
Scroll to Top