找到[a,b]范围内不在给定std :: set S中的所有数字

时间:2012-05-17 12:28:29

标签: c++ algorithm stl set

ab为整数,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:

ab的所有数字推送到set并使用std::set_difference

Solution1包含一个显式循环,而solution2似乎效率不高(至少在内存方面)。你会建议什么?我正在寻找一种优雅的STL-ish(提升也是可以接受的)惯用的方式来做到这一点。

4 个答案:

答案 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]中的所有整数。