二分查找真的有你想象中那么简单吗?
2016-03-04 10:59
381 查看
二分查找是查找算法里家喻户晓的算法了,其时间复杂度为O(logn),可是如果真的让你立马拿出笔写一个二分查找的函数出来,你确定你可以比较快的完全写对吗?
我们的目的是从一个已经按从小到大的顺序排序好的数组arr中查找值为value的元素的位置。
大体思路我们应该都很清楚:有三个游标,一个low在头,一个high在尾,还有一个mid指向中间,如果要检索的数据value比中间的元素arr[mid]小,那么应该在[low,mid)区间继续查找,即将high指向mid前面那个元素(也许你可能认为是指向mid元素的位置);如果要检索的数据value比中间的元素arr[mid]大,那么应该在(mid,high]区间继续查找,即将low指向mid后面那个元素(也许你可能认为是指向mid元素的位置)。一直执行这个步骤来缩小搜索区间直到找到arr[k]==value返回k
或 low>high时返回-1表示没找到。
其中的细节有很多是需要格外注意的。下面我就通过一个我的一段代码来引出需要注意的地方。
在看完了上面的代码后,你有木有想到代码中注释部分的问题?当你第一遍写代码的时候真的考虑到了吗,如果没考虑这些会有什么过果呢?下面让我们来一一道来:
(1)第六行如果写作mid = (high+low)/2;,有木有发现high+low有点蹊跷?如果你看出来了,恭喜你说明你对数据类型对应的取值范围很了解!当DataType定义为int型时,两个int相加,不要以为不会越界哈~另外改成移位操作同样完成了除以2一样的效果,但是效率却提高了。如果用移位的话一定要记得移位运算优先级很低,所以记得加括号!!记得加括号!括号!(重要的事说三遍,哈哈)
(2)第七行说好的判等呢,为嘛写成了区间的形式?这个嘛,就要考虑代码可重用性,因为细心的你可能会发现,传入的第一个参数是数组类型,什么类型的数组?这里暂时定义为int,那如果是float呢?double呢?判等还用==?所以这里考虑的是普遍情况,通过将两个数的差值在很小范围内来表示他们相等,int时照样适用。
(3)第10行第12行,才开始写的时候可能会纠结是不是要减1或者加1,当然还有第五行是写low <= high还是low < high?举几个让另一种情况出现问题的例子然后你就会明白其中的奥秘了。
转自:http://www.tuicool.com/articles/ruAZjy
我们的目的是从一个已经按从小到大的顺序排序好的数组arr中查找值为value的元素的位置。
大体思路我们应该都很清楚:有三个游标,一个low在头,一个high在尾,还有一个mid指向中间,如果要检索的数据value比中间的元素arr[mid]小,那么应该在[low,mid)区间继续查找,即将high指向mid前面那个元素(也许你可能认为是指向mid元素的位置);如果要检索的数据value比中间的元素arr[mid]大,那么应该在(mid,high]区间继续查找,即将low指向mid后面那个元素(也许你可能认为是指向mid元素的位置)。一直执行这个步骤来缩小搜索区间直到找到arr[k]==value返回k
或 low>high时返回-1表示没找到。
其中的细节有很多是需要格外注意的。下面我就通过一个我的一段代码来引出需要注意的地方。
1 typedef int DataType; 2 int binarySearch(const DataType arr[],const DataType value,size_t len) 3 { 4 int low = 0, high = len-1, mid; 5 while(low <= high) { 6 mid = low + ((high-low)>>1); //思考为什么不写作(high+low)/2; 7 if(value-arr[mid]<1e-6 && arr[mid]-value<1e-6)//思考为何不写作arr[mid]!=value 8 return mid; 9 if(value<arr[mid]) 10 high = mid-1; //如果写作high = mid;可以吗 11 else 12 low = mid+1; //如果写作low = mid;可以吗 13 } 14 return -1; 15 }
在看完了上面的代码后,你有木有想到代码中注释部分的问题?当你第一遍写代码的时候真的考虑到了吗,如果没考虑这些会有什么过果呢?下面让我们来一一道来:
(1)第六行如果写作mid = (high+low)/2;,有木有发现high+low有点蹊跷?如果你看出来了,恭喜你说明你对数据类型对应的取值范围很了解!当DataType定义为int型时,两个int相加,不要以为不会越界哈~另外改成移位操作同样完成了除以2一样的效果,但是效率却提高了。如果用移位的话一定要记得移位运算优先级很低,所以记得加括号!!记得加括号!括号!(重要的事说三遍,哈哈)
(2)第七行说好的判等呢,为嘛写成了区间的形式?这个嘛,就要考虑代码可重用性,因为细心的你可能会发现,传入的第一个参数是数组类型,什么类型的数组?这里暂时定义为int,那如果是float呢?double呢?判等还用==?所以这里考虑的是普遍情况,通过将两个数的差值在很小范围内来表示他们相等,int时照样适用。
(3)第10行第12行,才开始写的时候可能会纠结是不是要减1或者加1,当然还有第五行是写low <= high还是low < high?举几个让另一种情况出现问题的例子然后你就会明白其中的奥秘了。
转自:http://www.tuicool.com/articles/ruAZjy
相关文章推荐
- tableviewcell自适应cell高度
- windows下安装memcache
- servlet中常用方法
- 单独的一个模块如何安装
- Reeb 图
- Fragment(碎片)
- Android兼容包Support v4.v7.v13区别与应用场景
- mac 启动 进度条卡在一半处
- 深入浅出nodejs学习记录
- 关于Myeclipse修改默认编码,而content types中update不能更新问题
- spring filter的targetFilterLifecycle作用
- 英语学习
- android 比较靠谱的图片压缩
- IOS 多个UIImageView 加载高清大图时内存管理
- 3714: [PA2014]Kuglarz|贪心|思路题
- 如何给网页css样式起个好名字?
- AndroidStudio怎样导入jar包
- Hello World聚类代码(一)
- 创建ASM磁盘组时报磁盘组名称冲突的错误
- 机器学习——岭回归和LASSO回归