2017-08-03 58 views
2

我有两个容器std::setstd::vector,我的任务是返回中存在的std::vector中的元素。什么是最有效的方法来实现它? 简单解决方案: 遍历矢量元素,并在每个元素上调用set.find,然后vector.erase,如果未找到。在std :: set中查找std :: vector的元素

+3

矢量是排序还是未排序? – NathanOliver

+1

听起来像你可能需要像['std :: set_union'](http://en.cppreference.com/w/cpp/algorithm/set_union)(但它需要对矢量进行排序)。 –

+0

对不一致。暂时(并且可能保持不变)向量未排序且很小。集合有更多的元素,但。 – rublow

回答

0

你可以使用更多的STL :)

#include <algorithm> 
#include <set> 
#include <vector> 
#include <iostream> 
#include <iterator> 

int main() { 
    std::vector<int> v {5, 4, 3, 2, 1}; 
    std::set<int> s {1, 3, 5}; 

    v.erase(std::remove_if(v.begin(), v.end(), 
          [&s](int a) { return s.find(a) == s.end(); }), 
      v.end()); 

    std::copy(v.begin(), v.end(), std::ostream_iterator<int>(std::cout, " ")); 
} 
+0

因为我想保持向量中的元素存在于集合中,所以解决方案需要一个小的校正'return s.find(a)== s.end()'; – rublow

+0

@rublow - 已更正 – tmp

2

如何寻找每一个元素?如果您的载体没有排序,再有就是围绕n log(n)

#include <algorithm> 

std::vector<int> result; 
for(auto&& el: myvector) { 
    auto it_found = myset.find(el); 
    if(it != myset.end()) 
     result.push_back(*it_found); 
} 

没有办法现在result拥有所有那些在这两个元素。

PS:没有编译代码,可能会有轻微的错误。

+0

不是100%肯定,但不是这个O(n^2)?你不需要迭代vector,然后使用set的'find'成员函数来获得O(n log n)? – NathanOliver

+0

@NathanOliver其实我不确定。它可能是'n^2'。我有点不知所措,因为'std :: set'是排序的。 –

+0

但是你没有搜索这个集合。 'for(auto && el:myset)'遍历这些集合,使之成为'n',然后'std :: find(myvector.begin(),myvector.end(),el);'搜索另一个'那么'O(n^2)'对吗? – NathanOliver

0

您应该对矢量进行排序(如有必要,请保留原始索引,制作pair),然后使用binary search搜索矢量。这会更快。

或者您可以使用std::find方法,该方法可能会很慢。

+0

很确定你不想排序,如果它没有排序。排序是O(n log n),那么你有另一个O(n log n)进程。整个过程至少可以在一个O(n log n)过程中完成。 – NathanOliver

+0

对于一个单一的号码,你需要'n'的复杂性。由于集合中可以有多个数字,所以这个线性搜索必须重复。 – Ultraviolet

0

最短路可能是用std::set_intersection。但是,你应该排序向量,使其工作:

int main() 
{ 
    std::set<int> s{1,2,3,4,5,6,7,8}; 
    std::vector<int> v{7,5,10,9}; 
    std::sort(v.begin(), v.end()); // should not bother you if vector is small 

    std::vector<int> intersection; 
    std::set_intersection(s.begin(), s.end(), v.begin(), v.end(), std::back_inserter(intersection)); 

    for(int n : intersection) 
     std::cout << n << ' '; 
} 

打印:5 7

+0

如果我错了,纠正我,但它仍然是N logN – rublow

+1

如果'n'是向量的大小,'m'是该集合的大小,这是'O(n * lg(n)+ n +米)'。它可以在'O(n * lg(m))'中完成。 (并且设置迭代很慢。) – molbdnilo

0

根据集和载体的相对大小,可能的remove_if是正确的事情...

#include <set> 
#include <vector> 
#include <iostream> 
#include <algorithm> 

int main() 
{ 
    std::set<int> s{1,2,3,4,5,6,7,8}; 
    std::vector<int> v{7,5,10,9}; 

    v.erase(std::remove_if(v.begin(), v.end(), [&](int e){return s.count(e) == 0;}), v.end()); 


    for(int n : v) 
     std::cout << n << ' '; 
} 
0

如果你找最多CPU复杂方面这样做的 - 有效方式,具有额外的内存和一个好的哈希函数,你能做到在O(N + M):

std::vector<int> v; 
std::set<int> s; 
std::unordered_set<int> us{s.cbegin(), s.cend(), s.size()}; 

v.erase(
    std::remove_if(v.begin(), v.end(), 
     [&us] (const int entry) { return us.find(entry) == us.cend(); }), 
    v.end()); 

说明:您遍历您(O(m))准备unordered_set。然后你遍历你的vector一次(O(n)),每步执行unordered_set::find(0(1))。它给你O(n + m)的复杂性。

另外,unordered_set的大小等于set的大小,并且良好的散列函数有助于减少std::unordered_set::find的复杂性中的不变部分。

请参阅live example

但是,请记住,较低的复杂度并不一定意味着在特定情况下执行速度更快(例如,由于额外分配)。

+0

谢谢您的解释。然而(正如你所提到的),我想在不使用额外内存的情况下删除元素。 – rublow

+0

在这种情况下,如果你不关心set的属性或者使用[boost :: multi_index_container](http://www.boost.org/doc/libs/),你可以用'unordered_set'替换'set' 1_64_0/libs/multi_index/doc/tutorial/index.html),它使用'ordered_unique'索引类型来利用'set'类属性和'hashed_unique'来过滤O(n)复杂度不需要的条目。 –

相关问题