std::partition_point

来自cppreference.com
< cpp‎ | algorithm
 
 
算法库
受约束算法及范围上的算法 (C++20)
包含算法例如 ranges::copy, ranges::sort, ...
执行策略 (C++17)
排序和相关操作
划分操作
partition_point
(C++11)

排序操作
二分搜索操作(在已划分范围上)
集合操作(在有序范围上)
归并操作(在有序范围上)
堆操作
最小/最大操作
(C++11)
(C++17)
字典序比较操作
排列操作
C 库

数值运算
(C++11)                       
在未初始化内存上的操作
 
在标头 <algorithm> 定义
template< class ForwardIt, class UnaryPred >
ForwardIt partition_point( ForwardIt first, ForwardIt last, UnaryPred p );
(C++11 起)
(C++20 起为 constexpr)

检验(如同用 std::partition)已划分范围 [firstlast),并定位第一分段的结尾,即首个不满足 p 的元素,或者在所有元素满足 p 时是 last

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

参数

first, last - 要检验的已划分元素范围
p - 对于在范围起始找到的元素则返回 ​true 的一元谓词。

对每个(可为 const 的) VT 类型参数 v ,其中 VTForwardIt 的值类型,表达式 p(v) 必须可转换到 bool,无关乎值类别,而且必须不修改 v 。从而不允许 VT& 类型参数,亦不允许 VT ,除非对 VT 而言移动等价于复制 (C++11 起)。 ​

类型要求
-
ForwardIt 必须满足老式向前迭代器 (LegacyForwardIterator)
-
UnaryPred 必须满足谓词 (Predicate)

返回值

[firstlast) 内第一分段结尾后的迭代器。

复杂度

给定 Nstd::distance(first, last),应用 O(log(N)) 次谓词 p

注解

此算法是 std::lower_bound 的更通用化的形式,它可以表达为以 [&](const auto& e) { return e < value; }); 为谓词调用 std::partition_point

可能的实现

template<class ForwardIt, class UnaryPred>
constexpr //< C++20 起
ForwardIt partition_point(ForwardIt first, ForwardIt last, UnaryPred p)
{
    for (auto length = std::distance(first, last); 0 < length; )
    {
        auto half = length / 2;
        auto middle = std::next(first, half);
        if (p(*middle))
        {
            first = std::next(middle);
            length -= (half + 1);
        }
        else
            length = half;
    }
 
    return first;
}

示例

#include <algorithm>
#include <array>
#include <iostream>
#include <iterator>
 
auto print_seq = [](auto rem, auto first, auto last)
{
    for (std::cout << rem; first != last; std::cout << *first++ << ' ') {}
    std::cout << '\n';
};
 
int main()
{
    std::array v{1, 2, 3, 4, 5, 6, 7, 8, 9};
 
    auto is_even = [](int i) { return i % 2 == 0; };
 
    std::partition(v.begin(), v.end(), is_even);
    print_seq("划分后,v:", v.cbegin(), v.cend());
 
    const auto pp = std::partition_point(v.cbegin(), v.cend(), is_even);
    const auto i = std::distance(v.cbegin(), pp);
    std::cout << "划分点在 " << i << ";v[" << i << "] = " << *pp << '\n';
 
    print_seq("第一分段(所有偶数元素):", v.cbegin(), pp);
    print_seq("第二分段(所有奇数元素):", pp, v.cend());
}

可能的输出:

划分后,v:8 2 6 4 5 3 7 1 9
划分点在 4;v[4] = 5
第一分段(所有偶数元素):8 2 6 4
第二分段(所有奇数元素):5 3 7 1 9

参阅

寻找首个满足特定判别标准的元素
(函数模板)
(C++11)
检查范围是否已按升序排列
(函数模板)
返回指向第一个不小于 给定值的元素的迭代器
(函数模板)
定位已划分范围的划分点
(niebloid)