STL源码学习----lower_bound和upper_bound算法
转自:http://www.cnblogs.com/cobbliu/archive/2012/05/21/2512249.html
先贴一下自己的二分代码:
#include <cstdio>
#include <iostream>
using namespace std;
int a[]={,,,,,,,,,,,,};
int main()
{
//35 7 63 8
int l=,r=,m=(l+r)>>;
int p=;
while(l<r)
{
m=(l+r)>>;
//不加等号是upper 加等号是lower
//upper是找第一个大于的
//lower是找第一个大于等于的
if(a[m]>=p) //符合条件 找更符合条件的
r=m;
else //不符合条件
l=m+;
}
printf("%d\n",lower_bound(a,a+,p)-a);
//最后l=r 取的是l的值就对了
printf("%d %d %d\n",l,r,m);
return ;
}
STL中的每个算法都非常精妙,接下来的几天我想集中学习一下STL中的算法。
ForwardIter lower_bound(ForwardIter first, ForwardIter last,const _Tp& val)算法返回一个非递减序列[first, last)中的第一个大于等于值val的位置。
ForwardIter upper_bound(ForwardIter first, ForwardIter last, const _Tp& val)算法返回一个非递减序列[first, last)中第一个大于val的位置。
lower_bound和upper_bound如下图所示:

1, lower_bound
这个序列中可能会有很多重复的元素,也可能所有的元素都相同,为了充分考虑这种边界条件,STL中的lower_bound算法总体上是才用了二分查找的方法,但是由于是查找序列中的第一个出现的值大于等于val的位置,所以算法要在二分查找的基础上做一些细微的改动。
首先是我修改数据结构课本上的二分查找实现的lower_bound算法:
int my_lower_bound(int *array, int size, int key)
{
int first = , last = size-;
int middle, pos=; //需要用pos记录第一个大于等于key的元素位置 while(first < last)
{
middle = (first+last)/;
if(array[middle] < key){ //若中位数的值小于key的值,我们要在右边子序列中查找,这时候pos可能是右边子序列的第一个
first = middle + ;
pos = first;
}
else{
last = middle; //若中位数的值大于等于key,我们要在左边子序列查找,但有可能middle处就是最终位置,所以我们不移动last,
pos = last; //而是让first不断逼近last。
}
}
return pos;
}
STL中的实现比较精巧,下面贴出源代码:
//这个算法中,first是最终要返回的位置
int lower_bound(int *array, int size, int key)
{
int first = , middle;
int half, len;
len = size; while(len > ) {
half = len >> ;
middle = first + half;
if(array[middle] < key) {
first = middle + ;
len = len-half-; //在右边子序列中查找
}
else
len = half; //在左边子序列(包含middle)中查找
}
return first;
}
2, upper_bound
upper_bound返回的是第一个大于val的位置,也是有一个新元素val进来时的插入位置。
我依然将二分查找略做修改:
int my_upper_bound(int *array, int size, int key)
{
int first = , last = size-;
int middle, pos = ; while(first < last)
{
middle = (first+last)/;
if(array[middle] > key){ //当中位数大于key时,last不动,让first不断逼近last
last = middle;
pos = last;
}
else{
first = middle + ; //当中位数小于等于key时,将first递增,并记录新的位置
pos = first;
}
}
return pos;
}
下面的代码是STL中的upper_bound实现:
int upper_bound(int *array, int size, int key)
{
int first = , len = size-;
int half, middle; while(len > ){
half = len >> ;
middle = first + half;
if(array[middle] > key) //中位数大于key,在包含last的左半边序列中查找。
len = half;
else{
first = middle + ; //中位数小于等于key,在右半边序列中查找。
len = len - half - ;
}
}
return first;
}
STL源码学习----lower_bound和upper_bound算法的更多相关文章
- STL源码学习----lower_bound和upper_bound算法[转]
STL中的每个算法都非常精妙,接下来的几天我想集中学习一下STL中的算法. ForwardIter lower_bound(ForwardIter first, ForwardIter last,co ...
- [转] STL源码学习----lower_bound和upper_bound算法
http://www.cnblogs.com/cobbliu/archive/2012/05/21/2512249.html PS: lower_bound of value 就是最后一个 < ...
- stl源码学习(版本2.91)--list
stl源码学习(版本2.91)--list 一,阅读list()构造函数的收获 1,默认构造函数的作用和被调用的时机 struct no{ no(int i){} //no(){ // std::co ...
- 【STL源码学习】STL算法学习之二
第一章:前言 学习笔记,记录学习STL算法的一些个人所得,在以后想用的时候可以快速拾起. 第二章:明细 copy 函数原型: template <class InputIterator, cla ...
- 【STL源码学习】std::list类的类型别名分析
有了点模板元编程的traits基础,看STL源码清晰多了,以前看源码的时候总被各种各样的typedef给折腾得看不下去, 将<list>头文件的类继承结构简化如下 #include < ...
- 【STL源码学习】细品vector
第一节:vector简介 vector是一种典型的类模板,使用的时候必须进行实例化. vector的数据存储在数组上,支持随机访问迭代器,支持下标操作[]和at操作,支持手动扩容和自动容量增长. ve ...
- 【STL源码学习】STL算法学习之三
第一章:前言 数量不多,用到的时候会很爽. 第二章:明细 STL算法中的又一个分类:分割:将已有元素按照既定规则分割成两部分. is_partitioned 函数原型: template <c ...
- 【STL源码学习】STL算法学习之一
第一章:引子 STL包含的算法头文件有三个:<algorithm><numeric><functional>,其中最大最常用的是<algorithm>, ...
- 【STL源码学习】STL算法学习之四
排序算法是STL算法中相当常用的一个类别,包括部分排序和全部排序算法,依据效率和应用场景进行选择. 明细: sort 函数原型: template <class RandomAccessIter ...
随机推荐
- jQuery中的100个技巧
1.当document文档就绪时执行JavaScript代码. 我们为什么使用jQuery库呢?原因之一就在于我们可以使jQuery代码在各种不同的浏览器和存在bug的浏览器上完美运行. < ...
- jQuery_mobile页面跳转事件学习
<html> <head> <meta http-equiv="Content-Type" content="t ...
- Shiro-集成Spring
集成Spring 加入Spring 和Shiro的jar 包 配置Spring 及SpringMVC 参照:1.3.2\shiro-root-1.3.2-source-release\shiro-ro ...
- 企业站SEO记录
半个多月前给接了一个企业站,赚点小钱,客户也没什么要求,所以就找了模板修改了一下就上线了,然后又做了微信网站.搭了微信公众号,也都没什么技术含量,最伤脑筋的就是做关键词排名了,虽然做的几个词竞争也不是 ...
- PHP进程通信基础——shmop 、sem系列函数使用
PHP进程通信基础--shmop .sem系列函数使用 进程通信的原理就是在系统中开辟出一个共享区域,不管是管道也好,还是共享内存,都是这个原理.如果心中有了这个概念,就会很方便去理解代码.由于官网上 ...
- BZOJ2588: Spoj 10628. Count on a tree
传送门 刚开始看错题以为是dfs序瞎搞.. 后来看清题了开始想用树剖瞎搞... 感觉要滚粗啊.. 对于每个点到根的路径建立线段树,暴力建MLE没跑,上主席树,然后$(x,y)$的路径就可以先求出来$L ...
- Day8-面向对象进阶&&socket基础
抽象类 python2中的写法 import abc class Alert(object): '''报警基类''' __metaclass__ = abc.ABCMeta @abc.abstract ...
- 命令行提交本地项目到github上
1.github账号要有. 2.配置ssh key ① defaults write com.apple.finder AppleShowAllFiles -bool true 终端 显示隐 ...
- OpenStack三种类型的NAT转换
SNAT SNAT即源网络地址转换,这个NAT路由修改IP包包头中的源IP地址.SNAT功能通常用于让只具有私有IP地址的主机能够访问外网,比如,多个PC使用路由器共享上网,每个PC都配置了内网IP, ...
- Placeholder在IE8的兼容问题
<script type="text/javascript"> if( !('placeholder' in document.createElement('input ...