让a
和b
为整数,a < b
。给定std::set<int> S
什么是高效的和优雅(最好没有显式循环)方式来查找和存储(vector
)来自[a, b]
的所有数字不在S
。
解决方案1:
vector<int> v;
for(int i = a; i <= b; ++i)
{
if(S.find(i) == S.end())
{
v.push_back(i);
}
}
解决方案2:
将a
到b
的所有数字推送到set
并使用std::set_difference
Solution1包含一个显式循环,而solution2似乎效率不高(至少在内存方面)。你会建议什么?我正在寻找一种优雅的STL-ish(提升也是可以接受的)惯用的方式来做到这一点。
答案 0 :(得分:8)
你可以做类似你的解决方案#2。但是,不是创建包含范围[a,b]
的实际容器,而是使用boost::irange
,它是数值范围的虚容器。这样你就没有显式循环,它将以线性时间运行,而不会占用太多内存。
要使速度更快,请使用lower_bound
/ upper_bound
使其仅涵盖相关部分:
auto abRange = boost::irange(a,b+1);
std::set_difference(abRange.begin(), abRange.end(),
s.lower_bound(a), s.upper_bound(b),
std::back_inserter(resultVector));
或使用Boost.Range
的{{1}}:
set_difference
答案 1 :(得分:2)
set_intersection
中的“set”并不代表std::set
- 它只是表示逻辑集;一组事。如果两个集合都已排序,您可以只将set_intersection
两个放入第三个容器中。
vector<int> common;
set_intersection(v.begin(), v.end(), s.begin(), s.end(), back_inserter(common));
编辑:
这是一个完整的例子,说明了上述内容。这使用C ++ 11 lambdas,但是如果你没有C ++ 11或者不能使用lambdas,你可以使用functor代替它们。注意缺少显式循环。
#include <set>
#include <vector>
#include <algorithm>
#include <iterator>
#include <functional>
#include <iostream>
using namespace std;
static const int numbers[] = {0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181};
static const size_t num_numbers = sizeof(numbers)/sizeof(numbers[0]);
int main()
{
/*** GET THE SET ****/
set<int> s(begin(numbers), end(numbers));
//copy(&numbers[0], &numbers[num_numbers], inserter(s, s.begin()));
/*** GET THE NUMBERS TO LOOK FOR **/
int first = 5, last = 10;
vector<int> targets;
generate_n(back_inserter(targets), last-first, [&first]() -> int {
return first++;
});
/*** FIND THE INTERSECTION ***/
vector<int> common;
set_intersection(s.begin(), s.end(), targets.begin(), targets.end(), back_inserter(common));
/*** DUMP RESULTS ***/
cout << "Intersecton of:\n\t";
copy(s.begin(), s.end(), ostream_iterator<int>(cout,"\t"));
cout << "\nwith:\n\t";
copy(targets.begin(), targets.end(), ostream_iterator<int>(cout,"\t"));
cout << "\n= = = = = = = =\n\t";
copy(common.begin(), common.end(), ostream_iterator<int>(cout,"\t"));
cout << "\n";
}
输出是:
Intersecton of:
0 1 2 3 5 8 13 21 34
55 89 144 233 377 610 987 1597 2584 4181
with:
5 6 7 8 9
= = = = = = = =
5 8
答案 2 :(得分:2)
以下几点可以避免循环,但我不确定它是你之后的事情:
void inSet(int i, int b, vector<int>& v, set<int>& S)
{
if(S.find(i) == S.end())
v.push_back(i);
if(i<b)
inSet(i+1,b,v,S);
}
// ... snip
vector<int> v;
inSet(a,b,v,S);
此外,是否没有循环将所有整数[a,b]放入解决方案2中的std :: set中?
答案 3 :(得分:1)
您可以从S.lower_bound(a)
迭代到S.lower_bound(b)
并收集您找不到的所有整数:
auto end = S.lower_bound(b);
int seen = a;
for (auto it = S.lower_bound(a); it < end; ++it) {
for (int i = seen+1; i < *it; ++i)
v.push_back(i);
seen = *it;
}
它包含一个显式循环,但不知何故你必须查看[a,b]
中的所有整数。