zoukankan      html  css  js  c++  java
  • 二分查找

    有人说,90%的程序员都手写不出正确的二分查找

    没错,我就是那90%

    c++的标准库里只提供了binary_search(),lower_bound(),upper_bound()三个函数,缺点就是,只能在数组或者vector这样的线性数据结构上二分

    所以就需要整理一下二分的用法和代码

    1,binary_search(arr[],arr[]+size,key,cmp)

    功能:找到正好等于key的元素,成功则返回位置,否则返回数组末尾指针

    注意,给出的最后一个参数是比较函数的指针,如果不给出,默认调用标准库中的less()函数,其实就是小于号。

    这个是最好写的,不需要考虑左右边界或者失配的问题

    (伪)代码:

    int binary_search(arr[],arr[]+size,key,cmp) {
        int left = 0; 
        int right = nums.length - 1;
        while(left <= right) {
            int mid = (right + left) / 2;
            if(equal(arr[mid],key))
                return arr[]+mid; 
            else if (less(nums[mid],target))
                left = mid + 1;
            else 
                right = mid - 1;
            }
        return arr[]+size;
    }

    2,lower_bound(arr[],arr[]+size,key,cmp)

    这个函数的功能是找出第一个大于等于key的值,可以简记为左边界,和上一个函数不同的是,除非key值大于全部数组中的值,才会返回arr[]+size,否则一定会返回一个有效值。

    这个代码我写了n遍,查阅了m个博客,都挂了,最后发现,直接去看c++的手册它不香吗?

    template <class ForwardIterator, class T>
      ForwardIterator lower_bound (ForwardIterator first, ForwardIterator last, const T& val)
    {
      ForwardIterator it;
      iterator_traits<ForwardIterator>::difference_type count, step;
      count = distance(first,last);
      while (count>0)
      {
        it = first; step=count/2; advance (it,step);
        if (*it<val) {                 // or: if (comp(*it,val)), for version (2)
          first=++it;
          count-=step+1;
        }
        else count=step;
      }
      return first;
    }

    (伪)代码:

    int lower_bound (int l, int r, int key) {
        int it;
        int count,step;
        count = r-l+1;
        while (count>0) {
            step=count/2;
            it=l+step;
            if (a[it]<key) {
                l=it+1;
                count-=step+1;
            } else count=step;
        }
        return l;
    }

    注意,这个函数就比上一个难写很多,比如left,right为什么要小于等于,最后要返回的是left还是right,等等

    3,upper_bound(arr[],arr[]+size,key,cmp)

    这个函数的功能是找出大于key的第一个值的位置,简称右边界

    还是先查c++手册:

    template <class ForwardIterator, class T>
      ForwardIterator upper_bound (ForwardIterator first, ForwardIterator last, const T& val)
    {
      ForwardIterator it;
      iterator_traits<ForwardIterator>::difference_type count, step;
      count = std::distance(first,last);
      while (count>0)
      {
        it = first; step=count/2; std::advance (it,step);
        if (!(val<*it))                 // or: if (!comp(val,*it)), for version (2)
          { first=++it; count-=step+1;  }
        else count=step;
      }
      return first;
    }

    然后照猫画虎,写出(伪)代码:

    int upper_bound2 (int l,int r,int key) {
        int it;
        int count, step;
        count = r-l+1;
        while (count>0) {
            step=count/2;
            it=l+step;
            if ( a[it] <= key) {               
                l=it+1;
                count-=step+1;
            } else count=step;
        }
        return l;
    }

    这个函数常用于给整数开平方根或者类似的操作,因为大于key的第一个值,位置减去1,就是小于等于key的最后一个值

    涉及到给整数开平方根或者类似的操作的,一定记得用二分,不要自作聪明求解析解,然后转换成double,在cmath库里的函数求解,再转换回来,绝对不要!

    我是不会告诉你我被昨晚的atcoder arc的B题卡了一个多小时的,天知道,1e18的数据范围,他是怎么想到构造出卡掉double+sqrt的数据的

    代码正确性验证:

    洛谷P2249

    arc109B

    参考资料:

    https://www.cnblogs.com/kyoner/p/11080078.html

    http://www.cplusplus.com/reference/algorithm/

  • 相关阅读:
    Apache 虚拟主机 VirtualHost 配置
    EAX、ECX、EDX、EBX寄存器的作用
    Python中文文档 目录(转载)
    八度
    POJ 3268 Silver Cow Party (最短路)
    POJ 2253 Frogger (求每条路径中最大值的最小值,Dijkstra变形)
    2013金山西山居创意游戏程序挑战赛——复赛(1) HDU 4557 非诚勿扰 HDU 4558 剑侠情缘 HDU 4559 涂色游戏 HDU 4560 我是歌手
    HDU 4549 M斐波那契数列(矩阵快速幂+欧拉定理)
    UVA 11624 Fire! (简单图论基础)
    HDU 3534 Tree (树形DP)
  • 原文地址:https://www.cnblogs.com/isakovsky/p/14059913.html
Copyright © 2011-2022 走看看