遍历 std::set 中包含的所有三重不同值?

Go through all triple of different values contained in a std::set?

本文关键字:三重 set std 包含 遍历      更新时间:2023-10-16

假设我有一个没有重复值的排序向量。如果我想遍历不同值的所有三元组,我这样做:

for(std::size_t i = 0; i < data.size(); ++i)
for(std::size_t j = i+1; j < data.size(); ++j)
for(std::size_t k = j+1; k < data.size(); ++k)
do_somthing_with(data[i],data[j],data[k]);

如果我的容器是std::set,如何使用迭代器执行此操作?

注意:出于兼容性原因,我不使用 C++11。

你可以做与向量几乎相同的操作,但你需要创建一个包装函数,它将复制和递增集合迭代器:

std::set<int>::const_iterator next_iterator(std::set<int>::const_iterator it)
{
return ++it; // it has been passed by value, so already copied
}
//...
for (std::set<int>::const_iterator it = data.begin(); it != data.end(); ++it)
for(std::set<int>::const_iterator jt = next_iterator(it); jt != data.end(); ++jt)
for(std::set<int>::const_iterator kt = next_iterator(jt); kt != data.end(); ++kt)
// ...

你可以做这样的事情:

if (data.size() < 2) { return; }
for (auto it1 = data.begin(); it1 != std::prev(data.end(), 2); ++it1) {
for (std::size_t it2 = std::next(it1); it2 != std::prev(data.end()); ++it2) {
for (std::size_t it3 = std::next(it2); it3 != data.end(); ++it3) {
do_something_with(*it1, *it2, *it3);
}
}
}

您可以缓存std::prev的值。

这是从一组 n 个元素中选择所有 k 组合的特例。

有关解释,请参见此处:https://en.wikipedia.org/wiki/Combination

这在之前的堆栈溢出上已经得到了回答: 在C++中创建 n 个项目的所有可能的 k 组合

你可以把你的问题想象成你必须在向量示例中使用迭代器而不是索引。让我们以这种方式简化它:

for(std::size_t i = 0; i < data.size(); ++i)
do_somthing_with(data[i]);

你可以用迭代器这样写它:

for(std::vector<MyClass>::iterator it = data.begin(); it != data.end(); ++it)
do_somthing_with(*it);

现在对集合执行相同的操作非常简单:

for(std::set<MyClass>::iterator it = data.begin(); it != data.end(); ++it)
do_somthing_with(*it);

如果你想使用三重循环,在我看来,问题从下一个迭代器开始。使用 C++11,您可以使用 std::next,但由于您不能,您需要存储迭代器,然后推进它:

for(std::set<MyClass>::iterator it1 = data.begin(); it1 != data.end(); ++it1)
{
std::set<MyClass>::iterator it2 = it1;
++it2;
for(; it2 != data.end(); ++it2)
{
std::set<MyClass>::iterator it3 = it2;
++it3;
for(; it3 != data.end(); ++it3)
do_somthing_with(*it1,*it2,*it3);
}
}

或者,您可以定义自己的next函数,例如:

template<class ForwardIt>
ForwardIt next(ForwardIt it)
{
return ++it;
}

这基本上是 std::next 建议实现的简化版本。

然后可以更轻松地重写代码:

for(std::set<MyClass>::iterator it1 = data.begin(); it1 != data.end(); ++it1)
for(std::set<MyClass>::iterator it2 = next(it1); it2 != data.end(); ++it2)
for(std::set<MyClass>::iterator it3 = next(it2); it3 != data.end(); ++it3)
do_somthing_with(*it1,*it2,*it3);

你可以从中创建一个向量,然后按照你通常的方式去做。

std::set<int> s = {1, 2, 3, 4, 5, 6, 7};
std::vector<int> data(s.begin(), s.end());
for(std::size_t i = 0; i < data.size(); ++i)
for(std::size_t j = i+1; j < data.size(); ++j)
for(std::size_t k = j+1; k < data.size(); ++k)
do_somthing_with(data[i],data[j],data[k]);