std::upper_bound

来自cppreference.com
< cpp‎ | algorithm
 
 
算法库
受约束算法及范围上的算法(C++20)
包含算法例如 ranges::copy, ranges::sort, ...
执行策略 (C++17)
排序和相关操作
划分操作
排序操作
二分搜索操作(在已划分范围上)
upper_bound
集合操作(在有序范围上)
归并操作(在有序范围上)
堆操作
最小/最大操作
(C++11)
(C++17)
字典序比较操作
排列操作
C 库

数值运算
(C++11)                       
在未初始化内存上的操作
 
在标头 <algorithm> 定义
(1)
template<class ForwardIt, class T >

ForwardIt upper_bound( ForwardIt first, ForwardIt last,

                       const T& value );
(C++20 起为 constexpr)
(C++26 前)
template<class ForwardIt, class T =typenamestd::iterator_traits

                                         <ForwardIt>::value_type>
constexpr ForwardIt upper_bound( ForwardIt first, ForwardIt last,

                                 const T& value );
(C++26 起)
(2)
template<class ForwardIt, class T, class Compare >

ForwardIt upper_bound( ForwardIt first, ForwardIt last,

                       const T& value, Compare comp );
(C++20 起为 constexpr)
(C++26 前)
template<class ForwardIt, class T =typenamestd::iterator_traits

                                         <ForwardIt>::value_type,
          class Compare >
constexpr ForwardIt upper_bound( ForwardIt first, ForwardIt last,

                                 const T& value, Compare comp );
(C++26 起)

在已划分的范围 [firstlast) 中查找第一个后序于 value 的元素。

1) 通过 operator< 确定顺序:

返回 [firstlast) 中首个使得 bool(value <*iter)true 的迭代器 iter,或者在不存在这种 iter 的情况下返回 last

如果 [firstlast) 的元素 elem 没有按表达式 bool(value < elem)划分,那么行为未定义。

(C++20 前)

等价于 std::upper_bound(first, last, value, std::less{})

(C++20 起)
2) 通过 comp 确定顺序:
返回 [firstlast) 中首个使得 bool(comp(value, *iter))true 的迭代器 iter,或者在不存在这种 iter 的情况下返回 last
如果 [firstlast) 的元素 elem 没有按表达式 bool(comp(value, elem))划分,那么行为未定义。

目录

[编辑]参数

first, last - 要检验的已划分元素范围的迭代器对
value - 要与元素比较的值
comp - 如果第一个实参先序于第二个则返回 ​true 的二元谓词

谓词函数的签名应等价于如下:

 bool pred(const Type1 &a, const Type2 &b);

虽然签名不必有 const& ,函数也不能修改传递给它的对象,而且必须接受(可为 const 的)类型 Type1Type2 的值,无关乎值类别(从而不允许 Type1 &,亦不允许 Type1 ,除非 Type1 的移动等价于复制(C++11 起))。
类型 Type1 必须使得 T 类型的对象能隐式转换到 Type1。类型 Type2 必须使得 ForwardIt 类型的对象能在解引用后隐式转换到 Type2。 ​

类型要求
-
ForwardIt 必须满足老式向前迭代器(LegacyForwardIterator)
-
Compare 必须满足二元谓词(BinaryPredicate) 。不要求满足 比较(Compare)

[编辑]返回值

返回到范围 [firstlast) 的第一个后序于 value 的元素的迭代器,或者在找不到这种元素时返回 last

[编辑]复杂度

给定 Nstd::distance(first, last)

1,2) 最多应用 log2(N)+O(1)operator<(C++20 前)std::less{}(C++20 起) 进行比较。
3,4) 最多应用 log2(N)+O(1) 次比较函数 comp

然而,如果 ForwardIt 不是老式随机访问迭代器(LegacyRandomAccessIterator) ,那么迭代器自增次数与 N 成线性。要注意 std::mapstd::multimapstd::setstd::multiset 的迭代器不是随机访问的,因此它们的 upper_bound 成员函数的表现更好。

[编辑]可能的实现

参阅 libstdc++libc++ 中的实现。


upper_bound (1)
template<class ForwardIt, class T =typenamestd::iterator_traits<ForwardIt>::value_type> ForwardIt upper_bound(ForwardIt first, ForwardIt last, const T& value){return std::upper_bound(first, last, value, std::less{});}
upper_bound (2)
template<class ForwardIt, class T =typenamestd::iterator_traits<ForwardIt>::value_type, class Compare> ForwardIt upper_bound(ForwardIt first, ForwardIt last, const T& value, Compare comp){ ForwardIt it;typenamestd::iterator_traits<ForwardIt>::difference_type count, step; count =std::distance(first, last);   while(count >0){ it = first; step = count /2;std::advance(it, step);   if(!comp(value, *it)){ first =++it; count -= step +1;}else count = step;}   return first;}

[编辑]注解

尽管 std::upper_bound 只要求 [firstlast) 已划分,但是该算法通常会在 [firstlast) 已排序的情况下使用,此时二分查找对于任意 value 都有效。

对于 [firstlast) 中的任意迭代器 iterstd::upper_bound 要求 value <*itercomp(value, *iter) 良构,而 std::lower_bound 要求 *iter < valuecomp(*iter, value) 良构。

功能特性测试标准功能特性
__cpp_lib_algorithm_default_value_type202403(C++26)算法中的列表初始化(1,2)

[编辑]示例

#include <algorithm>#include <cassert>#include <complex>#include <iostream>#include <vector>   struct PriceInfo {double price;};   int main(){conststd::vector<int> data{1, 2, 4, 5, 5, 6};   for(int i =0; i <7;++i){// 搜索首个大于 i 的元素auto upper = std::upper_bound(data.begin(), data.end(), i);   std::cout<< i <<" < "; upper != data.end()?std::cout<<*upper <<" 位于索引 "<<std::distance(data.begin(), upper):std::cout<<"没有找到";std::cout<<'\n';}   std::vector<PriceInfo> prices ={{100.0}, {101.5}, {102.5}, {102.5}, {107.3}};   for(double to_find :{102.5, 110.2}){auto prc_info = std::upper_bound(prices.begin(), prices.end(), to_find, [](double value, const PriceInfo& info){return value < info.price;});   prc_info != prices.end()?std::cout<< prc_info->price <<" 位于索引 "<< prc_info - prices.begin():std::cout<< to_find <<" 没有找到";std::cout<<'\n';}   using CD =std::complex<double>;std::vector<CD> nums{{1, 0}, {2, 2}, {2, 1}, {3, 0}, {3, 1}};auto cmpz =[](CD x, CD y){return x.real()< y.real();};#ifdef __cpp_lib_algorithm_default_value_typeauto it = std::upper_bound(nums.cbegin(), nums.cend(), {2, 0}, cmpz);#elseauto it = std::upper_bound(nums.cbegin(), nums.cend(), CD{2, 0}, cmpz);#endifassert((*it == CD{3, 0}));}

输出:

0 < 1 位于索引 0 1 < 2 位于索引 1 2 < 4 位于索引 2 3 < 4 位于索引 2 4 < 5 位于索引 3 5 < 6 位于索引 5 6 < 没有找到 107.3 位于索引 4 110.2 没有找到

[编辑]缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

缺陷报告 应用于 出版时的行为 正确行为
LWG 270 C++98 Compare 需要满足比较(Compare) ,并且 T 需要是
可小于比较(LessThanComparable) 的(要求严格弱序)
只需要划分;
容许异相比较
LWG 384 C++98 最多允许 log2(N)+1 次比较 改成 log2(N)+O(1)
LWG 577 C++98 不能返回 last 可以返回
LWG 2150 C++98 如果 [firstlast) 中存在任何迭代器 iter 使得
bool(comp(value, *iter))true,那么
std::upper_bound 可以返回 [iterlast) 中的任意迭代器
不能返回 iter
后的迭代器

[编辑]参阅

返回匹配特定键值的元素范围
(函数模板)[编辑]
返回首个不小于 给定值的元素的迭代器
(函数模板)[编辑]
将范围中元素分为两组
(函数模板)[编辑]
定位已划分范围的划分点
(函数模板)[编辑]
返回首个大于 给定值的元素的迭代器
(算法函数对象)[编辑]
返回指向首个大于 给定键的元素的迭代器
(std::set<Key,Compare,Allocator> 的公开成员函数)[编辑]
返回指向首个大于 给定键的元素的迭代器
(std::multiset<Key,Compare,Allocator> 的公开成员函数)[编辑]
close