我有一个std::set
的集合。我希望以最快的方式找到此集合中所有集合的交集。集合中的集合数量通常非常小(~5-10),每个集合中的元素数量通常小于1000,但偶尔可以达到10000左右。但我需要做几十个交叉点成千上万的时间,尽可能快。我尝试按如下方式对几种方法进行基准测试:
std::set
对象中的就地交叉点。然后对于后续集合,它迭代自身的所有元素和集合的第i组,并根据需要从自身中删除项目。std::set_intersection
用于临时std::set
,将内容交换到当前集,然后再次找到当前集与下一集的交集并插入临时集,依此类推。vector
作为目标容器而不是std::set
。std::list
代替vector
,怀疑list
会从中间提供更快的删除。std::unordered_set
)并检查所有集合中的所有项目。事实证明,当每个集合中的元素数量较少时,使用vector
会稍微快一些,而对于较大的集合,list
稍微快一些。使用set
的就地比两者慢得多,其次是set_intersection
和哈希集。是否有更快的算法/数据结构/技巧来实现这一目标?如果需要,我可以发布代码片段。谢谢!
答案 0 :(得分:10)
您可能想尝试std::set_intersection()
的泛化:算法是对所有集合使用迭代器:
end()
,则表明您已完成。因此,可以假设所有迭代器都是有效的。x
。std::find_if()
第一个元素至少与x
一样大。x
,请将其作为新的候选值,并在迭代器序列中再次搜索。x
上,则找到了交集的元素:记录它,递增所有迭代器,重新开始。答案 1 :(得分:5)
夜晚是一个很好的顾问,我想我可能有一个想法;)
这就是为什么速度很重要的原因,vector
(或者可能是deque
)是如此伟大的结构:它们与记忆非常相配。因此,我肯定会建议使用vector
作为我们的中间结构;虽然需要注意只从极端插入/删除以避免重新定位。
所以我想到了一个相当简单的方法:
#include <cassert>
#include <algorithm>
#include <set>
#include <vector>
// Do not call this method if you have a single set...
// And the pointers better not be null either!
std::vector<int> intersect(std::vector< std::set<int> const* > const& sets) {
for (auto s: sets) { assert(s && "I said no null pointer"); }
std::vector<int> result; // only return this one, for NRVO to kick in
// 0. Check obvious cases
if (sets.empty()) { return result; }
if (sets.size() == 1) {
result.assign(sets.front()->begin(), sets.front()->end());
return result;
}
// 1. Merge first two sets in the result
std::set_intersection(sets[0]->begin(), sets[0]->end(),
sets[1]->begin(), sets[1]->end(),
std::back_inserter(result));
if (sets.size() == 2) { return result; }
// 2. Merge consecutive sets with result into buffer, then swap them around
// so that the "result" is always in result at the end of the loop.
std::vector<int> buffer; // outside the loop so that we reuse its memory
for (size_t i = 2; i < sets.size(); ++i) {
buffer.clear();
std::set_intersection(result.begin(), result.end(),
sets[i]->begin(), sets[i]->end(),
std::back_inserter(buffer));
swap(result, buffer);
}
return result;
}
似乎correct,显然我不能保证它的速度。