zoukankan      html  css  js  c++  java
  • 终极二分查找--传说十个人写九个有bug

    之前写过一篇极为罗嗦的二分查找,非常得意地以为以后就可以避免踩坑了,但是今天才知道二分查找可以写的既简洁又鲁棒,唉!还是要多学习啊!

    给一个按照从大到小的顺序排序好的数组a[]={1,2,3,4,7,7,7,8,9,10};

    用二分查找分别求等于4,大于7的第一个数,大于等于7的第一个数,小于7的最大的数,小于等于7的最大的数。

    如果写的不小心的话非常容易陷入死循环,有的时候写二分可能也会面临是l = mid还是l=mid+1这样的纠结,所以本文要证明,这几种查询的方式是可以

    统一在一起的,只需要重载元素的小于号,就可以完成所有的工作

    #include <bits/stdc++.h>
    using namespace std;
    int n;
    int a[] = {1,2,3,4,6,7,7,8,9,10};//以升序列为例,降序也一样道理
    
    bool cmp(int x,int v)
    {
        return x < v;//判断a[mid]和所要查找的边界值的关系,
    //我们只需要一个小于号就可以表示出大于,等于,小于,大于等于,小于等于,这也是为什么在sort里面需要重载小于号即可。 }
    int b_search(int a[],int n,int v)//精确查找数组里是不是有等于v的元素 { int l = -1,r = n;//把l,r预先设定成两个边界值,在查找大于小于的时候非常有用,下面再说。 for(int mid;r-l>1;){//强烈建议多用for,少用while mid = (l+r)>>1; if(!cmp(a[mid],v)&&!cmp(v,a[mid])) return mid;//如果a【mid】不小于v,反之也不成立,只能是相等了,直接返回地址 else if(cmp(a[mid],v)) l = mid+1;//a【mid】小于v此时a[mid]在v的右边,所以查找区间应该右移 else r = mid-1;//反之同理 } if(a[l] == v) return l;//如果最后得到的地址的值确实等于要查找的值,返回地址。 else return -1;//否则,返回-1 } int upperequal(int a[],int n,int v)//大于等于v的最小的数,相当于stl的lower_bound函数 { int l = -1,r = n;//这里有一个隐含的意思是l是小于v的,r是大于v的那个元素,一直保持这样就可以不陷入死循环 for(int mid;r-l>1;){ mid = (l+r)>>1; if(!cmp(a[mid],v)) r = mid;//注意这里判断的是a【mid】是不是大于等于v, else l = mid; } return r;//因为r在变化过程中一直是大于等于v的,所以r就是答案 } int upper(int a[],int n, int v)//二分查找大于v的第一个数,相当于stl里面的upperbound { int l = -1,r = n; for(int mid; r-l>1;){ mid = (l+r)>>1; if(cmp(v,a[mid])) r = mid; else l = mid; } return r; } int lower(int a[],int n, int v)//查找小于v的最大的元素 { int l = -1,r = n; for(int mid; r-l>1;){ mid = (l+r)>>1; if(cmp(a[mid],v)) l = mid; else r = mid; } return l; } int lowerequal(int a[],int n, int v)查找小于等于v的最大的元素 { int l = -1,r = n; for(int mid;r-l>1;){ mid=(l+r)>>1; if(!cmp(v,a[mid])) l = mid; else r = mid; } return l; } int main() { cout<<lowerequal(a,10,5)<<endl; }

    相信再也不会担心死循环了

  • 相关阅读:
    Node.js的安装与配置【转载】
    The Tomcat connector configured to listen on port 8080 failed to start. The port may already be in use or the connector【端口号被占用】
    MVC登陆认证简单设置
    Winform无边框窗体拖动
    Winform截图小程序
    C#Winform实时更新数据库信息Demo(使用Scoket)
    记DateTime.Now.ToString()遇到的一个坑
    T4模板的一些配置(从EF数据更新)
    设计模式之策略模式
    打造高效的研发组织架构:高效研发流程那些事(一)——读《技术领导力实战笔记》摘要
  • 原文地址:https://www.cnblogs.com/Norlan/p/5031850.html
Copyright © 2011-2022 走看看