C++中的无序集合交集

unordered set intersection in C++

本文关键字:集合 无序 C++      更新时间:2023-10-16

这是我的代码,想知道有什么想法可以使其更快吗?我的实现是蛮力,它是针对 a 中的任何元素,尝试查找它是否也在 b 中,如果是,则放入结果集 c。任何更聪明的想法都会受到赞赏。

#include <iostream>
#include <unordered_set>
int main() {
std::unordered_set<int> a = {1,2,3,4,5};
std::unordered_set<int> b = {3,4,5,6,7};
std::unordered_set<int> c;
for (auto i = a.begin(); i != a.end(); i++) {
if (b.find(*i) != b.end()) c.insert(*i);
}
for (int v : c) {
std::printf("%d n", v);
}
}

渐近地,你的算法是最好的。

在实践中,我会添加一个检查来循环两个集合中较小的一个,并在较大的集合中进行查找。假设哈希分布合理均匀,std::unoredered_set中的查找需要恒定的时间。因此,这样,您将执行更少的此类查找。

你可以用std::copy_if()来做到这一点

std::copy_if(a.begin(), a.end(), std::inserter(c, c.begin()), [b](const int element){return b.count(element) > 0;} );

对于无序集合,您的算法与它一样好。 但是,如果您使用std::set(使用二叉树作为存储)甚至更好的排序std::vector,则可以做得更好。算法应该是这样的:

  1. 让迭代器a.begin()b.begin()
  2. 如果迭代器
  3. 指向相等元素,则添加到交集并递增两个迭代器。
  4. 否则,将
  5. 指向最小值的迭代器递增
  6. 转到 2。

两者都应该是 O(n) 时间,但使用普通集合应该可以避免计算哈希或哈希冲突引起的任何性能下降。

谢谢 Angew,为什么你的方法更快?你能详细说明一下吗?

好吧,让我为您提供一些额外的信息...

应该很清楚的是,无论您使用哪种数据结构,您都必须迭代其中至少一个中的所有元素,因此您不能比O(n)更好,n是数据结构中选择要迭代的元素数量。现在的基本问题是,你可以多快地查找另一个结构中的元素——使用哈希集,实际上是std::unordered_set,这是O(1)的——至少如果碰撞次数足够小("合理均匀分布的哈希">);退化的情况将是所有具有相同键的值...

到目前为止,你得到O(n) * O(1) = O(n).但是你仍然可以选择:O(n)O(m),如果m是另一个集合中的元素数量。好的,在复杂度计算中,这是相同的,反正我们有一个线性算法,但在实践中,如果你选择元素数量较少的集合,你可以省去一些哈希计算和查找......