lower_bound

lower_bound(begin, end, target)用来查找一个已排序的序列中[begin, end)第一个大于等于target的元素index。数组A如下:

value: 1, 2, 2, 3, 4, 5, 5, 6, 7

index: 0, 1, 2, 3, 4, 5, 6, 7, 8

这样的一个序列,如果查找5的lower_bound,返回的应该是第一个5即A[5]。下面是摘自cplusplus.com上的lower_bound代码

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>)
{
it = first; step=count/; advance (it,step);
if (*it < val) { // or: if (comp(*it,val)), for version (2)
first = ++it;
count -= step+;
}
else count = step;
}
return first;
}

如果搜索对象只是数组的话还可以再简化一点:

count = last - start;
while (count > ) {
step = count/;
int* it = first + step;
if (*it < target) {
count = count - (step + );
first = it + ;
} else {
count=step;
}
}
return first;

基本情况: 当输入只有一个元素时,而该元素不是要查找的元素时返回last,即该元素的后一个位置

case: target=4

当在上图中的数组中找4的lower_bound时,第一次*it取到的值是4,因为这不是简单的二分搜索,而是要返回第一大于等于查找元素的位置,所以搜索不能在此时结束。但是可以确定5~7这一部分可以不用搜索了,因为当前至少有一个元素即*it是大于等于4了,因而缩小查找范围(count=step)。这个查找范围并不包括已找到的4,为什么是这样?分情况讨论:

1. 当前面的这个范围没有符合条件的数时,就会将范围最后的位置的后一位置返回,而此位置正好是4所在的位置(*it>= target时it所在的位置,它是符合查找条件的),其正好是lower_bound。

2. 当前面的这个方位含有符合条件的数时,此时当前的这个4就不是lower_bound,真正的lower_bound会在该区间内产生

case: target=5

当求5的lower_bound时,第一次找到中间元素时4,4<5,所以4和4前面的所有都不会含有5的lower_bound,因而下一次搜索只会在5~7这个区间进行,这个就和一个全新的问题一样了。

upper_bound

upper_bound用来在[begin, end)中找到第一个大于target的index

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>)
{
it = first; step=count/; std::advance (it,step);
if (!(val<*it)) // or: if (!comp(val,*it)), for version (2)
{ first=++it; count-=step+; }
else count=step;
}
return first;
}

简化版本:

lower_bound:

         int lo = , hi = n;
// lower_bound
while (lo < hi) {
int mid = (lo + hi) / ;
if (A[mid] < target) {
lo = mid + ;
} else {
hi = mid;
}
} return lo;

upper_bound:

        lo = , hi = n;
// upper_bound
while (lo < hi) {
int mid = (lo + hi) / ;
if (A[mid] <= target) {
lo = mid + ;
} else {
hi = mid;
}
}
return lo;

就在判断条件上多了个等号

C++ STL:lower_bound与upper_bound实现的更多相关文章

  1. [STL] lower_bound和upper_bound

    STL中的每个算法都非常精妙, ForwardIter lower_bound(ForwardIter first, ForwardIter last,const _Tp& val)算法返回一 ...

  2. C++ STL lower_bound()和upper_bound()

    lower_bound()和upper_bound()用法 1.在数组上的用法 假设a是一个递增数组,n是数组长度,则 lower_bound(a, a+n, x):返回数组a[0]~a[n-1]中, ...

  3. STL源码学习----lower_bound和upper_bound算法

    转自:http://www.cnblogs.com/cobbliu/archive/2012/05/21/2512249.html 先贴一下自己的二分代码: #include <cstdio&g ...

  4. STL lower_bound upper_bound binary-search

    STL中的二分查找——lower_bound .upper_bound .binary_search 二分查找很简单,原理就不说了.STL中关于二分查找的函数有三个lower_bound .upper ...

  5. STL中的lower_bound和upper_bound的理解

    STL迭代器表述范围的时候,习惯用[a, b),所以lower_bound表示的是第一个不小于给定元素的位置 upper_bound表示的是第一个大于给定元素的位置. 譬如,值val在容器内的时候,从 ...

  6. STL 源码分析《5》---- lower_bound and upper_bound 详解

    在 STL 库中,关于二分搜索实现了4个函数. bool binary_search (ForwardIterator beg, ForwardIterator end, const T& v ...

  7. STL源码学习----lower_bound和upper_bound算法[转]

    STL中的每个算法都非常精妙,接下来的几天我想集中学习一下STL中的算法. ForwardIter lower_bound(ForwardIter first, ForwardIter last,co ...

  8. [转] STL源码学习----lower_bound和upper_bound算法

    http://www.cnblogs.com/cobbliu/archive/2012/05/21/2512249.html PS: lower_bound of value 就是最后一个 < ...

  9. STL之std::set、std::map的lower_bound和upper_bound函数使用说明

    由于在使用std::map时感觉lower_bound和upper_bound函数了解不多,这里整理并记录下相关用法及功能. STL的map.multimap.set.multiset都有三个比较特殊 ...

  10. STL中的二分查找——lower_bound 、upper_bound 、binary_search

    STL中的二分查找函数 1.lower_bound函数 在一个非递减序列的前闭后开区间[first,last)中.进行二分查找查找某一元素val.函数lower_bound()返回大于或等于val的第 ...

随机推荐

  1. Elasticsearch5.4 删除type

    首先要说明的是现在的Elasticsearch已经不支持删除一个type了,所以使用delete命令想要尝试删除一个type的时候会出现如下错误,如果存在一个名为edemo的index和tets的ty ...

  2. JavaScript创建对象的4种方法

    我们有很多种方式去构造一个对象.可以构造一个对象字面量,也可以和new前缀连用去调用一个构造器函数,或者可以使用Object.create方法去构造一个已经存在的对象的新实例,还可以调用任意一个会返回 ...

  3. 2. C++11 构造函数相关

    1. 继承构造函数 派生类如果要使用基类的成员函数,可以通过using声明来完成. #include <iostream> using namespace std; class Base ...

  4. linux常见编辑命令

    保存命令 按ESC键 跳到命令模式,然后: :w 保存文件但不退出vi :w file 将修改另外保存到file中,不退出vi :w! 强制保存,不推出vi :wq 保存文件并退出vi :wq! 强制 ...

  5. java中复制bean

    BeanUtils.copyProperties(p,d); p是等待被赋值的对象,d是源对象,将d中属性值赋值的p中对应的字段,d中有的属性p中必须有,p可以有更多属性

  6. 新手入门贴之基于 python 语言的接口自动化 demo 小实战

    大家好,我是正在学习接口测试的菜鸟.近期通过自己的学习,完成了一个关于测试接口的接口自动化demo.下面想跟大家分享一下,主要的思路是根据接口文档确定测试用例,并将测试用例写在excel中.因为只是小 ...

  7. ZJOI2019 day2 游记

    应该是打的最没有信仰的一次比赛了 然后这个垃圾水平居然还拿了170,真是有毒 我的语文并不好所以还是写流水账吧 day-2 到了余姚,发现附近并没有什么好吃的,于是直接去kfc了 另外潮湿的空气对呼吸 ...

  8. 【算法笔记】A1022 Digital Library

    题意 输入n本书的信息:id,书名,作者,关键字,出版社,出版年份.搜索图书,输出id. 思路 定义5个map<string, set<int> >,分别存放Title, Au ...

  9. Codeforces Round #555 (Div. 3) D. N Problems During K Days 【数学思维】

    一 题面 D. N Problems During K Days 二 分析 对于这题,刚开始我就是陷入了对公式的执着,企图用公式直接确定第一个数,然后试着去找序列.经过思考和手动模拟后发现是很难保证正 ...

  10. Java 线程类别

    Java 线程类别 守护线程和非守护线程 守护线程和非守护线程之前的唯一区别在于:是否阻止JVM的正常退出. JVM正常退出是与异常退出相对的概念,异常退出如调用System.exit(status) ...