std::ranges::is_permutation
来自cppreference.com
| 在标头 <algorithm> 定义
|
||
| 调用签名 |
||
| |
(1) | (C++20 起) |
| |
(2) | (C++20 起) |
1) 若存在范围
[first1, last1) 中的元素的排列使得该范围等于 [first2, last2)(在应用对应的投影 Proj1 和 Proj2 后,并以 Pred 为比较器)则返回 true。否则返回 false。2) 同 (1),但以
r1 为第一源范围并以 r2 为第二源范围,如同以 ranges::begin(r1) 为 first1,以 ranges::end(r1) 为 last1,以 ranges::begin(r2) 为 first2,并以 ranges::end(r2) 为 last2。此页面上描述的函数式实体是算法函数对象(非正式地称为 niebloid),即:
参数
| first1, last1 | - | 第一元素范围的迭代器-哨位对 |
| first2, last2 | - | 第二元素范围的迭代器-哨位对 |
| r1 | - | 第一元素 range
|
| r2 | - | 第二元素 range
|
| pred | - | 应用到投影后元素的谓词 |
| proj1 | - | 应用到第一范围中元素的投影 |
| proj2 | - | 应用到第一范围中元素的投影 |
返回值
若范围 [first1, last1) 为 [first2, last2) 的重排列则为 true。
复杂度
至多应用 O(N2) 次谓词和每个投影,或若序列已经相等则恰好应用 N 次,其中 N 为 ranges::distance(first1, last1)。
然而若 ranges::distance(first1, last1) != ranges::distance(first2, last2),则不应用谓词和投影。
注解
排列 关系是等价关系。
ranges::is_permutation 可以用于测试,比如检查诸如排序、混洗、划分等重排算法的正确性。若 p 为原序列而 q 是“改动后”的序列,则 ranges::is_permutation(p, q) == true 表示构成 q 的元素与 p 的“相同”(可能经过重排)。
可能的实现
struct is_permutation_fn
{
template<std::forward_iterator I1, std::sentinel_for<I1> S1,
std::forward_iterator I2, std::sentinel_for<I2> S2,
class Proj1 = std::identity, class Proj2 = std::identity,
std::indirect_equivalence_relation<std::projected<I1, Proj1>,
std::projected<I2, Proj2>>
Pred = ranges::equal_to>
constexpr bool operator()(I1 first1, S1 last1, I2 first2, S2 last2,
Pred pred = {}, Proj1 proj1 = {}, Proj2 proj2 = {}) const
{
// 跳过公共前缀
auto ret = std::ranges::mismatch(first1, last1, first2, last2,
std::ref(pred), std::ref(proj1), std::ref(proj2));
first1 = ret.in1, first2 = ret.in2;
// 在剩余部分迭代,统计每个来自 [first1, last1) 中的元素在 [first2, last2) 中出现多少次
for (auto i {first1}; i != last1; ++i)
{
const auto i_proj {std::invoke(proj1, *i)};
auto i_cmp = [&]<typename T>(T&& t)
{
return std::invoke(pred, i_proj, std::forward<T>(t));
};
if (i != ranges::find_if(first1, i, i_cmp, proj1))
continue; // 已检查过此 *i
if (const auto m {ranges::count_if(first2, last2, i_cmp, proj2)};
m == 0 or m != ranges::count_if(i, last1, i_cmp, proj1))
return false;
}
return true;
}
template<ranges::forward_range R1, ranges::forward_range R2,
class Proj1 = std::identity, class Proj2 = std::identity,
std::indirect_equivalence_relation<
std::projected<ranges::iterator_t<R1>, Proj1>,
std::projected<ranges::iterator_t<R2>, Proj2>>
Pred = ranges::equal_to>
constexpr bool operator()(R1&& r1, R2&& r2, Pred pred = {},
Proj1 proj1 = {}, Proj2 proj2 = {}) const
{
return (*this)(ranges::begin(r1), ranges::end(r1),
ranges::begin(r2), ranges::end(r2),
std::move(pred), std::move(proj1), std::move(proj2));
}
};
inline constexpr is_permutation_fn is_permutation{};
|
示例
运行此代码
#include <algorithm>
#include <array>
#include <cmath>
#include <iostream>
#include <ranges>
auto& operator<<(auto& os, std::ranges::forward_range auto const& v)
{
os << "{ ";
for (const auto& e : v)
os << e << ' ';
return os << "}";
}
int main()
{
static constexpr auto r1 = {1, 2, 3, 4, 5};
static constexpr auto r2 = {3, 5, 4, 1, 2};
static constexpr auto r3 = {3, 5, 4, 1, 1};
static_assert(
std::ranges::is_permutation(r1, r1) &&
std::ranges::is_permutation(r1, r2) &&
std::ranges::is_permutation(r2, r1) &&
std::ranges::is_permutation(r1.begin(), r1.end(), r2.begin(), r2.end()));
std::cout
<< std::boolalpha
<< "is_permutation(" << r1 << ", " << r2 << "): "
<< std::ranges::is_permutation(r1, r2) << '\n'
<< "is_permutation(" << r1 << ", " << r3 << "): "
<< std::ranges::is_permutation(r1, r3) << '\n'
<< "is_permutation with custom predicate and projections: "
<< std::ranges::is_permutation(
std::array{ -14, -11, -13, -15, -12 }, // 第一范围
std::array{ 'F', 'E', 'C', 'B', 'D' }, // 第二范围
[](int x, int y) { return abs(x) == abs(y); }, // 谓词
[](int x) { return x + 10; }, // 第一范围的投影
[](char y) { return int(y - 'A'); }) // 第二范围的投影
<< '\n';
}
输出:
is_permutation({ 1 2 3 4 5 }, { 3 5 4 1 2 }): true
is_permutation({ 1 2 3 4 5 }, { 3 5 4 1 1 }): false
is_permutation with custom predicate and projections: true
