C ++ 11包含算法std::partition_point()
。但是,对于所有我尝试过的情况,它给出的答案与std::lower_bound()
相同。唯一的区别是方便的T& value
参数。
我是否错过了某些事情,或者这两个功能或多或少在做同一件事?
答案 0 :(得分:13)
它们基本上是等效的。这将是lower_bound
的有效实现:
template <typename ForwardIterator, typename T>
ForwardIterator lower_bound(ForwardIterator first, ForwardIterator last,
T const& value)
{
return partition_point(first, last, [&](auto&& elem) {
return elem < value;
});
}
template <typename ForwardIterator, typename T, typename Compare>
ForwardIterator lower_bound(ForwardIterator first, ForwardIterator last,
T const& value, Compare comp)
{
return partition_point(first, last, [&](auto&& elem) {
return comp(elem, value);
});
}
这两种算法都依赖于找到分区范围的划分点,它们只是采用不同的参数进行搜索(partition_point
的一元谓词,而{{1}的值或值和二元谓词) }。
我们通常只在带有二进制谓词的排序范围内考虑lower_bound
,即使相对于这样的谓词的完全排序范围是not a requirement for that algorithm。
在使用lower_bound
的情况下,upper_bound
也可以用partition_point
的方式实现,只需将操作数翻转而将谓词取反即可。
template <typename ForwardIterator, typename T>
ForwardIterator upper_bound(ForwardIterator first, ForwardIterator last,
T const& value)
{
return partition_point(first, last, [&](auto&& elem) {
return !(value < elem);
});
}
template <typename ForwardIterator, typename T, typename Compare>
ForwardIterator upper_bound(ForwardIterator first, ForwardIterator last,
T const& value, Compare comp)
{
return partition_point(first, last, [&](auto&& elem) {
return !comp(value, elem);
});
}
奇怪的是,两者的措词有何不同。
lower_bound
returns(upper_bound
的措词是similar):
期间范围
i
中最远的迭代器[first, last]
,使得对于范围j
的每个迭代器[first, i)
,以下对应条件成立:*j < value
或{ {1}}。
迭代器
comp(*j, value) != false
,使得mid
和all_of(first, mid, pred)
均为none_of(mid, last, pred)
。
这些短语是等效的,因为要求是对范围进行分区。但是乍看之下肯定不是那样。
答案 1 :(得分:4)
它们都使用二进制搜索算法(用于随机访问迭代器)。
std::lower_bound
要求根据表达式(element < value
或comp(element, value)
(二进制)谓词(strike)划分的范围(strike)进行分类(这种情况如果范围是根据二进制谓词排序的。)std::partition_point
要求根据(一元)谓词对范围进行分区。您确实可以创建一个谓词以使用其他算法。
使用:
const std::vector<int> v{1, 2, 3, 4, 5, 6, 7, 8};
您可以使用lower_bound
:
assert(std::is_sorted(v.begin, v.end(), std::less<>));
auto it1 = std::lower_bound(v.begin, v.end(), 5, std::less<>);
或使用partition_point
:
auto pred = [](int e){ return e < 5; }
assert(std::is_partition(v.begin, v.end(), pred));
auto it2 = std::partition_point(v.begin, v.end(), pred);
assert(it1 == it2); // *it1 = 5
或者,另一面
const std::vector<int> v{1, 3, 4, 2, 7, 5, 8, 6};
您可以使用partition_point
:
auto pred = [](int e){ return e < 5; }
assert(std::is_partition(v.begin, v.end(), pred));
auto it1 = std::partition_point(v.begin, v.end(), pred);
或使用lower_bound
:
auto pred2 = [](int lhs, int rhs){ return (lhs < 5) > (rhs < 5); }
assert(std::is_sorted(v.begin, v.end(), pred2));
auto it2 = std::lower_bound(v.begin, v.end(), 5, pred2);
assert(it1 == it2); // *it1 == 7
答案 2 :(得分:3)
它们或多或少等效,只是如果没有提供谓词,lower_bound
将使用operator<
搜索元素。* partition_point
更为通用,因为它允许范围是根据某些通用谓词而不是针对a value
的谓词进行分区的。
请注意,lower_bound
大大早于C ++中更通用的分区概念的存在。
*,并且在很大程度上暗示lower_bound
中使用的谓词应满足小于关系,尽管不是必需的
来自[alg.partitions]
template<class ForwardIterator, class Predicate>
ForwardIterator partition_point(ForwardIterator first, ForwardIterator last, Predicate pred);
要求:ForwardIterator’s
值类型应可转换为Predicate’s
自变量类型。 [first, last)
应该由pred
进行分区,即,所有满足pred
的元素都应出现在满足这些条件的元素之前
不是。
返回:中间的迭代器,使得all_of(first, mid, pred)
和none_of(mid, last, pred)
为
都正确。
复杂度:O(log(last - first))
的{{1}}个应用程序。
并且从[lower.bound]
pred
要求:template<class ForwardIterator, class T>
ForwardIterator
lower_bound(ForwardIterator first, ForwardIterator last,
const T& value);
template<class ForwardIterator, class T, class Compare>
ForwardIterator
lower_bound(ForwardIterator first, ForwardIterator last,
const T& value, Compare comp);
的元素e
应相对于表达式[first, last)
或e < value
进行分区。
返回:范围comp(e, value)
中最远的迭代器i
,这样对于迭代器中的每个迭代器[first, last]
范围j
符合以下条件:[first, i)
或*j < value
。
复杂度:最多comp(*j, value) != false
个比较。