在大卫哈曼的回答之后,我试图解释为什么我们经常觉得lower_bound
/的名字upper_bound
不正确,或者至少不直观。
这是因为我们正在寻找一个低于查询的元素。我画了一张图和一个用例:
代码:
template< typename T, typename U >
auto infimum(std::map<T,U> const& ctr, T query)
{
auto it = ctr.upper_bound(query);
return it == ctr.begin() ? ctr.cend() : --it;
}
template< typename T, typename U >
bool is_in_interval(std::map<T,U> const& ctr, T query)
{
auto inf = infimum(ctr, query);
return inf == ctr.end() ? false : query <= inf->second;
}
https://ideone.com/jM8pt3
基本上要获得“灰色箭头”的行为,我们需要upper_bound - 1
这就是为什么它很奇怪。
让我稍微改一下:从lower_bound
我们本能地期望的名字returns-first-immediately-inferior-element
(如灰色箭头)。但是我们得到returns-first-immediately-superior-element
了lower_bound;和first-immediately-strictly-superior-element
上限。这就是令人惊讶的地方。
令人惊讶的是,假设您使用的是上图中我的思想实验这样的稀疏序列。equal_range
但是,当您按照密集序列中的“边界”来考虑它时,它会很有意义,其中充满了高原,就像美丽的 Kerrek SB 描绘的那样。
测试代码:
#include <map>
#include <cassert>
#include <iostream>
// .. paste infimum and is_in_interval here
int main()
{
using std::cout;
using Map = std::map<int,int>;
Map intervals{{2,5}, {8,9}};
auto red = infimum(intervals, 4);
assert(red->first == 2);
cout << "red->first " << red->first << "\n";
auto green = infimum(intervals, 6);
assert(green->first == 2);
cout << "green->first " << green->first << "\n";
auto pink = infimum(intervals, 8);
assert(pink->first == 8);
cout << "pink->first " << pink->first << "\n";
auto yellow = infimum(intervals, 1);
assert(yellow == intervals.cend());
auto larger_than_all = infimum(intervals, 15);
assert(larger_than_all->first == 8);
bool red_is = is_in_interval(intervals, 4);
cout << "red is in " << red_is << "\n";
bool green_is = is_in_interval(intervals, 6);
cout << "green is in " << green_is << "\n";
bool pink_is = is_in_interval(intervals, 8);
cout << "pink is in " << pink_is << "\n";
bool yellow_is = is_in_interval(intervals, 1);
cout << "yellow is in " << yellow_is << "\n";
}
结果是
red->first 2
green->first 2
pink->first 8
red is in 1
green is in 0
pink is in 1
yellow is in 0
似乎还可以。
所以当然实用函数不是很好,它们应该设计一个范围 API,所以我们可以使用任何集合或子范围,或者反向迭代器,或者过滤视图等等。当我们拥有 C++20 时,我们可以做到这一点。与此同时,我刚刚制作了一个简单的教育性地图绘制 API。
玩它:
https ://ideone.com/jM8pt3