STL 源码分析《5》---- lower_bound and upper_bound 详解
在 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 详解的更多相关文章
- ZRender源码分析5:Shape绘图详解
回顾 上一篇说到:ZRender源码分析4:Painter(View层)-中,这次,来补充一下具体的shape 关于热区的边框 以圆形为例: document.addEventListener('DO ...
- Jvm(jdk8)源码分析1-java命令启动流程详解
JDK8加载源码分析 1.概述 现在大多数互联网公司都是使用java技术体系搭建自己的系统,所以对java开发工程师以及java系统架构师的需求非常的多,虽然普遍的要求都是需要熟悉各种java开发框架 ...
- jQuery 源码分析(十八) ready事件详解
ready事件是当DOM文档树加载完成后执行一个函数(不包含图片,css等),因此它的触发要早于load事件.用法: $(document).ready(fun) ;fun是一个函数,这样当DOM树加 ...
- jQuery 源码分析(十一) 队列模块 Queue详解
队列是常用的数据结构之一,只允许在表的前端(队头)进行删除操作(出队),在表的后端(队尾)进行插入操作(入队).特点是先进先出,最先插入的元素最先被删除. 在jQuery内部,队列模块为动画模块提供基 ...
- vuex 源码分析(七) module和namespaced 详解
当项目非常大时,如果所有的状态都集中放到一个对象中,store 对象就有可能变得相当臃肿. 为了解决这个问题,Vuex允许我们将 store 分割成模块(module).每个模块拥有自己的 state ...
- Netty源码分析之Reactor线程模型详解
上一篇文章,分析了Netty服务端启动的初始化过程,今天我们来分析一下Netty中的Reactor线程模型 在分析源码之前,我们先分析,哪些地方用到了EventLoop? NioServerSocke ...
- 10.Spark Streaming源码分析:Receiver数据接收全过程详解
原创文章,转载请注明:转载自 听风居士博客(http://www.cnblogs.com/zhouyf/) 在上一篇中介绍了Receiver的整体架构和设计原理,本篇内容主要介绍Receiver在 ...
- mybatis 源码分析(三)Executor 详解
本文将主要介绍 Executor 的整体结构和各子类的功能,并对比效率: 一.Executor 主体结构 1. 类结构 executor 的类结构如图所示: 其各自的功能: BaseExecutor: ...
- mybatis 源码分析(八)ResultSetHandler 详解
本篇博客就是 myabtis 系列的最后一篇了,还剩 ResultSetHandler 没有分析:作为整个 mybatis 最复杂最繁琐的部分,我不打算按步骤一次详解,因为里面的主要内容就是围绕 re ...
- mybatis 源码分析(七)KeyGenerator 详解
一.KeyGenerator 概述 在平时开发的时候经常会有这样的需求,插入数据返回主键,或者插入数据之前需要获取主键,这样的需求在 mybatis 中也是支持的,其中主要的逻辑部分就在 KeyGen ...
随机推荐
- centos7配置mono和jexus5.6.2
一.通过集成包安装mono: 1.添加Mono的 包库源: 把Mono Project public Jenkins GPG signing 导入系统 wget http://jenkins.mon ...
- java的HashMap与ConcurrentHashMap
好像今天没有什么源码读,那么就来看看java的这两种HashMap有啥不一样的地方吧,在这之前先普及一下HashMap的一些基本知识: (1)放入HashMap的元素是key-value对. (2)底 ...
- listbox鼠标拖动数据和为button注册快捷键
将listbox1中的数据用鼠标拖动至listbox2,即有左至右. 分别对应控件注册如下事件DragEnter,MouseDown,DragDrop 代码如下: //P128 DataGridVie ...
- java对于文件传输时---编码格式的一些设置方法
- ----转 读文件: BufferedReader 从字符输入流中读取文本,缓冲各个字符,从而提供字符.数组和行的高效读取. 可以指定缓冲区的大小,或者可使用默认的大小.大多数情况下,默认值就足够 ...
- OC 实例变量(Instance Var)和成员变量(member var)区别
摘要: Objective-C 引入了“实例变量"的概念,但同时, 也经常出现 “成员变量”的声音. 到底什么是实例变量,什么是成员变量,二者的区别是什么呢? 今天查看apple 的官方 ...
- Python输出内容的三种方式:print输出 python脚本执行 linux直接执行
1. 在linux中安装python后,在linux命令行中输入python即可切换到Python命令行下 退出python命令行的命令: 老版本:ctrl+D 新版本:quit();或exit() ...
- 探究linux文件
一.Linux的文件: 文件名区分大小写:Linux没有文件拓展名:文件名支持长文件名,含空格,少部分标点符号. - _最好不要用空格 1 GUI图形用户界面:让简单的问题更加简单: CLI命令行界面 ...
- SQL Server数据库(SQL Sever语言 事务)
事务:保障流程的完整执行保证程序某些程序在运行时同时成功同时失败,保证程序的安全性 begin tran --在流程开始的位置加 --此处写SQL语句 if @@error>0 --ERRORS ...
- Java 正则表达式 向前、向后匹配
//向后匹配 String a = "I paid $90 for 10 oranges, 12 pears and 8 apples. I saved $5 on "; Patt ...
- Android开发--TextView的应用
1.概述 TextView主要用于Activity中文本的应用.其中layout中xml文件(activity)设置文本的宽度,高度,ID:values中strings.xml设置文本内容. Text ...