C++ 在std::set中查找std::vector的元素

C++ 在std::set中查找std::vector的元素,c++,c++11,vector,stl,set,C++,C++11,Vector,Stl,Set,我有两个容器std::set和std::vector,我的任务是从std::vector返回std::set中存在的元素。实现这一目标最有效的方法是什么? 简单解决方案: 迭代向量的元素并调用set。在每个元素上查找,然后再查找vector。如果未找到,则删除。只查找每个元素如何?如果向量未排序,则无法绕过n log(n) #包括 std::向量结果; 用于(自动(&el:myvector){ auto it_found=myset.find(el); if(it!=myset.end()) 结

我有两个容器
std::set
std::vector
,我的任务是从
std::vector
返回
std::set
中存在的元素。实现这一目标最有效的方法是什么? 简单解决方案:
迭代向量的元素并调用
set。在每个元素上查找
,然后再查找
vector。如果未找到,则删除

只查找每个元素如何?如果向量未排序,则无法绕过
n log(n)

#包括
std::向量结果;
用于(自动(&el:myvector){
auto it_found=myset.find(el);
if(it!=myset.end())
结果。推回(*找到它);
}
现在,
result
包含了两者中的所有元素


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

最短的方法可能是使用
std::set\u 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 << ' ';
}
intmain()
{
std::集s{1,2,3,4,5,6,7,8};
std::向量v{7,5,10,9};
std::sort(v.begin(),v.end());//若向量很小,则不应打扰您
向量交;
std::set_交叉点(s.begin()、s.end()、v.begin()、v.end()、std::back_插入器(交叉点));
用于(整数n:交点)

std::cout根据集合和向量的相对大小,删除\u如果可能是正确的

#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 << ' ';
}
#包括
#包括
#包括
#包括
int main()
{
std::集s{1,2,3,4,5,6,7,8};
std::向量v{7,5,10,9};
v、 擦除(std::remove_if(v.begin(),v.end(),[&](int e){返回s.count(e)==0;}),v.end());
对于(整数n:v)
std::cout您可以使用更多STL:)

#包括
#包括
#包括
#包括
#包括
int main(){
std::向量v{5,4,3,2,1};
std::集s{1,3,5};
v、 擦除(标准::如果(v.begin(),v.end(),则删除),
[&s](int a){返回s.find(a)==s.end();}),
v、 end());
std::copy(v.begin()、v.end()、std::ostream_迭代器(std::cout,“”);
}
如果您在复杂性方面寻找cpu效率最高的方法,并且有额外的内存和良好的哈希函数,您可以在O(n+m)中完成:

std::vector v;
std::集s;
无序的{s.cbegin(),s.cend(),s.size()};
v、 抹去(
如果(v.begin(),v.end(),则删除,
[&us](const int entry){返回us.find(entry)=us.cend();}),
v、 end());
说明:您在
集合上迭代一次(O(m))以准备
无序集
。然后您在
向量上迭代一次(O(n)),每一步执行
无序集::find
(0(1))。它给出了O(n+m)的结果复杂性

另外,
unordered_set
的大小等于
set
的大小,一个好的散列函数有助于减少
std::unordered_set::find
复杂度中的常量部分


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

向量是已排序的还是未排序的?听起来您可能想要类似的东西(但需要对向量进行排序)。抱歉,不一致。暂时(它可能保持不变)向量未排序且很小。但是集合有更多的元素。不是100%确定,但这不是O(n^2)?您不需要迭代向量,然后使用集合的
find
成员函数来获取O(n log n)?@NathanOliver实际上我不确定。它可能是
n^2
。我有点不知所措,因为
std::set
已排序。但您没有搜索集合。
for(auto&&el:myset)
迭代集合,即
n
然后
std::find(myvector.begin(),myvector.end(),el);
搜索另一个
n
的向量,这就是
O(n^2)
对吗?@NathanOliver是的,你是对的。我猜它是
n^2
。我相信如果你把它翻过来,你会得到
O(n log n)
。如果
n
是向量的大小,
m
是集合的大小,这就是
O(n*lg n+n+m)
。这可以在
O(n*lg(m))
中完成(设置迭代非常慢)。谢谢您的解释。但是(如您所述)我想在不使用额外内存的情况下“动态”删除元素。在这种情况下,如果您不关心
set
的排序属性,或者使用
ordered\u unique
索引类型使用
set
类属性和
hashed\u unique
,则可以将
set
替换为
unordered\u set
以O(n)复杂度剔除不需要的条目。由于我希望将集合中存在的元素保留在向量中,因此解决方案需要进行少量更正
返回s.find(a)==s.end()
#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 << ' ';
}
#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, " "));
}
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());