遍历 std::set 中包含的所有三重不同值?
Go through all triple of different values contained in a std::set?
假设我有一个没有重复值的排序向量。如果我想遍历所有不同值的三元组,我会这样做:
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。
这是从一组n个元素中选择所有k个组合的特例。
请看这里的解释:https://en.wikipedia.org/wiki/Combination
之前在 Whosebug 上已经回答过这个问题:
creating all possible k combinations of n items in C++
您可以从中创建一个矢量,然后按照您通常的方式进行操作。
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]);
你可以这样做:
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
的值。
您可以执行与向量几乎相同的操作,但您需要创建一个包装函数,它将复制和递增集合迭代器:
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)
// ...
您可以将您的问题想象成您必须在矢量示例中对索引使用迭代器。让我们这样简化它:
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;
}
这基本上是suggested implementation of 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);
假设我有一个没有重复值的排序向量。如果我想遍历所有不同值的三元组,我会这样做:
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。
这是从一组n个元素中选择所有k个组合的特例。
请看这里的解释:https://en.wikipedia.org/wiki/Combination
之前在 Whosebug 上已经回答过这个问题: creating all possible k combinations of n items in C++
您可以从中创建一个矢量,然后按照您通常的方式进行操作。
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]);
你可以这样做:
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
的值。
您可以执行与向量几乎相同的操作,但您需要创建一个包装函数,它将复制和递增集合迭代器:
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)
// ...
您可以将您的问题想象成您必须在矢量示例中对索引使用迭代器。让我们这样简化它:
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;
}
这基本上是suggested implementation of 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);