在 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. selenium+python笔记4

    #!/usr/bin/env python # -*- coding: utf-8 -*- """ @desc: 使用unittest组织用例 ""& ...

  2. robotframework笔记14

    创建用户关键字 关键字表是用于创建新的更高层次的关键词 结合现有的关键词. 这些关键字被称为 用户 关键字 区分他们的最低水平 库关键字 实现在测试库. 的语法创建用户 关键词非常接近的语法创建测试用 ...

  3. [saiku] 集成单点登录

    思路: 自定义一个loginCallbackFilter用于单点登录成功后执行模拟用户认证授权登录的操作. 当授权成功后所有配置需要授权才能访问的url就再也不会被任何filter拦截,可随意访问了. ...

  4. Qt之坐标系统

    简述 坐标系统是由QPainter类控制的,再加上QPaintDevice和QPaintEngine类,就形成了Qt的绘图体系. QPainter:用于执行绘图操作. QPaintDevice:二维空 ...

  5. Reverse Linked List II [LeetCode]

    Reverse a linked list from position m to n. Do it in-place and in one-pass. For example:Given 1-> ...

  6. iOS开发中你是否遇到这些经验问题

    前言 小伙伴们在开发中难免会遇到问题, 你是如何解决问题的?不妨也分享给大家!如果此文章其中的任何一条问题对大家有帮助,那么它的存在是有意义的! 反正不管怎样遇到问题就要去解决问题, 在解决问题的同时 ...

  7. 51nod 1050 循环数组最大子段和

    题目链接:51nod 1050 循环数组最大子段和 #include<stdio.h> #include<algorithm> using namespace std; ; l ...

  8. 最小生成树练习1(克鲁斯卡尔算法Kruskal)

    今天刷一下水题练手入门,明天继续. poj1861 Network(最小生成树)新手入门题. 题意:输出连接方案中最长的单根网线长度(必须使这个值是所有方案中最小的),然后输出方案. 题解:本题没有直 ...

  9. chrome 模拟点击

    实现进入一个页面后触发一个<a>的点击事件. 由于safari和chrome不支持<a>的click()所以需要对浏览器进行判断 var Sys = {};   var ua ...

  10. JDE变量说明

    BC Business view columns. Columns that are included in the attached business view. These columns are ...