在 STL 库中,关于二分搜索实现了4个函数。

bool binary_search (ForwardIterator beg, ForwardIterator end, const T& value)

判断 [beg, end) 中是否存在 value 的值。

ForwardIterator

lower_bound (ForwardIterator beg, ForwardIterator end, const T& value)

ForwardIterator

upper_bound (ForwardIterator beg, ForwardIterator end, const T& value)

搜寻第一个或者最后一个可能位置。

具体是什么意思呢?

1. lower_bound 指的是 返回第一个 ”大于等于 value“ 的元素位置。

另一种解释是 可插入”元素值为 value“且 ”不破坏有序性“的第一个位置

2. upper_bound 指的是 返回第一个 “大于 value ” 的元素位置;

另一种解释是 可插入”元素值为 value“且 ”不破坏有序性“的最后一个位置

举个例子: 1 2 2 3 4 5

value = 2: 则 lower_bound 返回的位置是 第 1 个位置;

upper_bound 返回的位置是 第 3 个位置。

大家可以看到一个很有意思的性质:

upper_bound - lower_bound = 数组中 value 的个数



下面我们来研究下 lower_bound 和 upper_bound 的实现。

以下是我按照源码改写的一个版本:

// return the first element which >= x
int LowerBound(int *a, int n, int x)
{
int left(0), right(n-1), mid; while(left <= right){
mid = left + ((right - left) >> 1);
if(a[mid] < x){
left = mid + 1;
}
else{
right = mid - 1;
}
} return left;
} // return first element which > x
int UpperBound(int *a, int n, int x)
{
int left(0), right(n-1), mid; while(left <= right){
mid = left + ((right - left) >> 1);
if(a[mid] <= x){
left = mid + 1;
}
else{
right = mid - 1;
}
} return left;
}

大家知道,在 STL 库中,区间一般采用半闭半开区间 [begin, last),

这种做法的好处是 last - begin 就是区间元素的个数。

以下是 STL 中的源码:

template <class _ForwardIter, class _Tp, class _Distance>
_ForwardIter __lower_bound(_ForwardIter __first, _ForwardIter __last,
const _Tp& __val, _Distance*)
{
_Distance __len = 0;
distance(__first, __last, __len);
_Distance __half;
_ForwardIter __middle; while (__len > 0) {
__half = __len >> 1;
__middle = __first;
advance(__middle, __half);
if (*__middle < __val) {
__first = __middle;
++__first;
__len = __len - __half - 1;
}
else
__len = __half;
}
return __first;
}

lower_bound的一个应用:

最长递增子序列问题:分析见  http://blog.csdn.net/shoulinjun/article/details/13775177

代码如下:

int LIS(int *a, int n)
{
if(n <= 0) return 0;
vector<int> maxV;
maxV.push_back(a[0]);
for(int i=0; i<n; ++i)
{
if(a[i] > *maxV.rbegin())
maxV.push_back(a[i]);
else
*lower_bound(maxV.begin(), maxV.end(), a[i]) = a[i];
}
return maxV.size();
}

STL 源码分析《5》---- lower_bound and upper_bound 详解的更多相关文章

  1. ZRender源码分析5:Shape绘图详解

    回顾 上一篇说到:ZRender源码分析4:Painter(View层)-中,这次,来补充一下具体的shape 关于热区的边框 以圆形为例: document.addEventListener('DO ...

  2. Jvm(jdk8)源码分析1-java命令启动流程详解

    JDK8加载源码分析 1.概述 现在大多数互联网公司都是使用java技术体系搭建自己的系统,所以对java开发工程师以及java系统架构师的需求非常的多,虽然普遍的要求都是需要熟悉各种java开发框架 ...

  3. jQuery 源码分析(十八) ready事件详解

    ready事件是当DOM文档树加载完成后执行一个函数(不包含图片,css等),因此它的触发要早于load事件.用法: $(document).ready(fun) ;fun是一个函数,这样当DOM树加 ...

  4. jQuery 源码分析(十一) 队列模块 Queue详解

    队列是常用的数据结构之一,只允许在表的前端(队头)进行删除操作(出队),在表的后端(队尾)进行插入操作(入队).特点是先进先出,最先插入的元素最先被删除. 在jQuery内部,队列模块为动画模块提供基 ...

  5. vuex 源码分析(七) module和namespaced 详解

    当项目非常大时,如果所有的状态都集中放到一个对象中,store 对象就有可能变得相当臃肿. 为了解决这个问题,Vuex允许我们将 store 分割成模块(module).每个模块拥有自己的 state ...

  6. Netty源码分析之Reactor线程模型详解

    上一篇文章,分析了Netty服务端启动的初始化过程,今天我们来分析一下Netty中的Reactor线程模型 在分析源码之前,我们先分析,哪些地方用到了EventLoop? NioServerSocke ...

  7. 10.Spark Streaming源码分析:Receiver数据接收全过程详解

    原创文章,转载请注明:转载自 听风居士博客(http://www.cnblogs.com/zhouyf/)   在上一篇中介绍了Receiver的整体架构和设计原理,本篇内容主要介绍Receiver在 ...

  8. mybatis 源码分析(三)Executor 详解

    本文将主要介绍 Executor 的整体结构和各子类的功能,并对比效率: 一.Executor 主体结构 1. 类结构 executor 的类结构如图所示: 其各自的功能: BaseExecutor: ...

  9. mybatis 源码分析(八)ResultSetHandler 详解

    本篇博客就是 myabtis 系列的最后一篇了,还剩 ResultSetHandler 没有分析:作为整个 mybatis 最复杂最繁琐的部分,我不打算按步骤一次详解,因为里面的主要内容就是围绕 re ...

  10. mybatis 源码分析(七)KeyGenerator 详解

    一.KeyGenerator 概述 在平时开发的时候经常会有这样的需求,插入数据返回主键,或者插入数据之前需要获取主键,这样的需求在 mybatis 中也是支持的,其中主要的逻辑部分就在 KeyGen ...

随机推荐

  1. Ubuntu 下 Neo4j单机安装和集群环境安装

    1. Neo4j简介 Neo4j是一个用Java实现的.高性能的.NoSQL图形数据库.Neo4j 使用图(graph)相关的概念来描述数据模型,通过图中的节点和节点的关系来建模.Neo4j完全兼容A ...

  2. mouseover,mouseenter,mouseleave,mouseout

    mouseover和mouseout对应 //鼠标移入移出触发该元素及子元素 mouseenter和mouseleave对应 //鼠标移入移出只触发该元素 看完例子即可知道其区别: mouseover ...

  3. Qt之加载QSS文件

    简述 Qt中关于样式的使用很常见,为了降低耦合性(与逻辑代码分离),我们通常会定义一个QSS文件,然后编写各种部件(例如:QLable.QLineEdit.QPushButton)的样式,最后使用QA ...

  4. jdbc URL中的各个参数详解

    常用的有两个,一个是gjt(Giant JavaTree)组织提供的mysql驱动,其JDBC Driver名称(Java类名)为:org.gjt.mm.mysql.Driver 详情请参见网站:ht ...

  5. oracle第一章

    1.oracle对比sqlserver oracle sqlserver 数据文件.dbf 数据文件.mdf 控制文件.ctl   日志文件.log 日志文件.log     2.内置用户 1.sys ...

  6. JButton计数

    1.引言 在Swing窗口中,我们时常会点击按钮进行计数,例如点击按钮A,第一次弹出窗口1,第二次弹出窗口2....以及按钮的快捷键设置. import java.awt.event.ActionEv ...

  7. echart饼状图的学习

    一.引入js文件 <!--Step:1 引入一个模块加载器,如esl.js或者require.js--> <script src="~/Scripts/esl.js&quo ...

  8. PHP函数——is_subclass_of() 函数 判断一个对象是否为一个类的子类

    说明: bool is_subclass_of ( object $object , string $class_name ) 如果对象 object所属类是类 class_name的子类,则返回 T ...

  9. was7中文redhat6上安装出现中文乱码解决方案

    转:http://blog.csdn.net/w1985g/article/details/8789378 在rhel-server-6.1-x86_64上安装WebSphere 7时,安装界面出现中 ...

  10. 如何实现301的跳转?当输入域名http://xxx.com的时候自动重定向到www上去

    答案:在服务器上操作,注意勾选和不勾选的区别,使用Fiddle进行观察,301和302之间的区别