zoukankan      html  css  js  c++  java
  • 【转】你真的会二分查找吗?

    转自:http://blog.csdn.net/int64ago/article/details/7425727

    红色字体为我对此转载文章的批注

    看到这个标题无论你是处于怎样的心理进来看了,我觉得都是值得的。因为这个问题太简单,任何一个开始接触“真正”算法基本都是从二分查找开始的。至于二分查找都不知道是什么的可以先去找别的资料看下,再来看这篇文章。既然很简单,那么我们开始一起写一个吧,要求是对num[]={1,2,2,4,4,8,10}不减序列在区间[0,7)进行查找,当然我们得首先保证要查找的数e满足:num[0] <= e <= num[0],这个是很容易做到的,为了简化又不失去代表性,e选取2、3、4这三个数。我们就一起开始写吧:

           首先,很容易的写下 int bSearch(int begin, int end, int e)

           然后,很自然的定义 int mid, left = begin, right = end;

           接下来怎么写呢?while(left < right)?while(left <= right)?while(mid == left)?while(mid == right)?………………真正一个写程序人会想纠结好一会儿,我们就选一个吧while(left < right)

           下面,也很自然,min = (left + right) >> 1; 用位云算能节省一些时间呢!

            现在呢?又是纠结的时候了吧?if(num[mid] > e)?if(num[mid] >= e)?我们也随便选一个吧,if(num[mid] > e)

            其实,下面你会不断纠结……right = mid;这是正常人的写法,但是有时候也会看到别人写成right = mid - 1;我们也考虑下吧,但是现在我们就直接写right = mid;

            有if了当然也会有else,然后理所当然 left = mid;同样记住还有一个选择left = mid + 1;

    不错,整个while循环搞定了,最后就是返回了,写下return的时候是不是又纠结了?left?right?mid?算了,就写mid吧,整个程序就写好了,如下:

    [cpp] view plain copy

    print?

    1. int bSearch(int begin, int end, int e)  
    2. {  
    3. int mid, left = begin, right = end;  
    4. while(left < right)  
    5.     {  
    6.         mid = (left + right) >> 1;  
    7. if(num[mid] > e) right = mid;  
    8. else left = mid;  
    9.     }  
    10. return mid;  

    补充好整个程序后运行吧!查找2、3、4的时候都没有结果出现!!比如查4的时候,单步调试会发现当mid=4,left=4,right=5,接下来就一直在while里循环,保持不变!问题到底在哪?问题在很多地方,因为我们上面的遇到很多选择,没有结果是多个选择作用的共同的结果,通过修修补补也可以得到想要的结果,其它例子就不举了,直接说说本文章讨论的关键吧。我总结的二分无非就4种情况:YES_LEFT、YES_RIGHT、NO_LEFT、NO_RIGHT,分别代表:能找到且返回最左边的数的位置(如查找4的时候返回位置3)、能找到且返回最右边的数的位置(如查找4的时候返回位置4)、不能找到且返回左边与其接近的数的位置(如查找3的时候返回位置2)、不能找到且返回右边与其接近的数的位置(如查找3的时候返回位置3)。下面是我总结调试的代码:

    红色标注为两者不同之处,黄色部分是需要特别注意的地方

    对于YES_LEFT或者NO_RIGHT

    int bSearch(int begin, int end, int e)  
    {  
    int mid, left = begin, right = end;  
    while(left <= right)  
        {  
            mid = (left + right) >> 1;  
    if(num[mid] >= e) right = mid - 1;  
    else left = mid + 1;  
        }  
    return left;  
    }

    对于YES_RIGHT或者NO_LEFT

    int bSearch(int begin, int end, int e)  
    {  
    int mid, left = begin, right = end;  
    while(left <= right)  
        {  
            mid = (left + right) >> 1;  
    if(num[mid] > e) right = mid - 1;  
    else left = mid + 1;  
        }  
    return right;  
    }

    不做过多说明,单步调试自然会发现执行过程,要说明的是,两个程序都用了right = mid - 1; left = mid +1;用这个的前提是终止条件要是left <= right 。模拟一下left与right差为2,e位于left+1的情况即可)要注意的是,有的二分查找不是只需要四种情况中的一种,而是组合使用,比如查找一个数,如果找到则×××不然则×××,如果是YES_LEFT || NO_RIGHT组合或者YES_RIGHT || NO_LEFT组合就直接用上面代码即可,否则就要综合用了,加一些判断等说明,因为用的时候不多,就不给出代码了,自己如果遇到可以试着写写,当成模板,以后直接用~

           现在,是不是觉得二分查找很容易呢?如果总结过的话……

  • 相关阅读:
    20165218 《网络对抗技术》Exp7 网络欺诈防范
    20165218 《网络对抗技术》Exp6 信息收集与漏洞扫描
    20165218 《网络对抗技术》 Exp5 MSF基础应用
    20165218 《网络对抗技术》Exp4 恶意代码分析
    20165218 《网络对抗技术》Exp3 免杀原理与实践
    20165218 《网络对抗技术》Exp2 后门原理与实践
    20165218 《网络对抗技术》Exp1 逆向及Bof基础
    20165218 《网络对抗技术》Exp0 Kali安装 Week1
    2018-2019-2 20165227《网络对抗技术》Exp9 Web安全基础
    2018-2019-2 网络对抗技术 20165227 Exp8 Web基础
  • 原文地址:https://www.cnblogs.com/liuzhanshan/p/6345619.html
Copyright © 2011-2022 走看看