partition_point和lower_bound有什么区别?

时间:2018-06-26 19:24:38

标签: c++ c++11 std partitioning binary-search

C ++ 11包含算法std::partition_point()。但是,对于所有我尝试过的情况,它给出的答案与std::lower_bound()相同。唯一的区别是方便的T& value参数。

我是否错过了某些事情,或者这两个功能或多或少在做同一件事?

3 个答案:

答案 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 returnsupper_bound的措词是similar):

  

范围i中最远的迭代器[first, last],使得对于范围j的每个迭代器[first, i),以下对应条件成立:*j < value或{ {1}}。

partition_point returns

期间
  

迭代器comp(*j, value) != false,使得midall_­of(first, mid, pred)均为none_­of(mid, last, pred)

这些短语是等效的,因为要求是对范围进行分区。但是乍看之下肯定不是那样。

答案 1 :(得分:4)

它们都使用二进制搜索算法(用于随机访问迭代器)。

  • std::lower_bound要求根据表达式(element < valuecomp(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个比较。

相关问题