找到集合并集的最快方法
The fastest way to find union of sets
我有一组像 int 一样的 int 对 set<pair<int,int> > x1, x2, ... xn
(n 可以介于 2 和 20 之间)。找到这些集合并集的最快方法是什么?
抱歉,如果我一开始没有说清楚,我的意思是性能快,内存分配不是问题。
假设结果也需要是一个集合,那么您别无选择,只能将每个x_i
的每个元素插入到该结果集中。所以显而易见的实现是:
set<pair<int,int>> x(x1);
x.insert(x2.begin(), x2.end());
// etc
剩下的问题是这是否可以在速度上被击败。
单元素insert
采用position
提示,如果正确,则会加快插入速度。所以结果可能是这样的事情比x.insert(x2.begin(), x2.end());
快:
auto pos = x.begin()
for (auto it = x2.begin(); it != x2.end(); ++it) {
pos = x.insert(pos, *it);
}
不过,这取决于数据:该位置可能准确,也可能不准确。您可以通过在开始之前将所有元素整理好来确保它,为此最好的工具可能是 set_union
.这最好命名为merge_and_dedupe_sorted_ranges
,因为它所做的与std::set
没有特别的关系。你可以set_union
到中间向量中,或者变成这样的集合:
set<pair<int,int>> x;
set_union(x1.begin(), x1.end(), x2.begin(), x2.end(), inserter(x, x.end());
我对使用 set_union
的担忧是,为了获得以递增顺序将元素添加到集合中的好处,每次调用它时都需要创建一个新的空容器(因为如果它不为空,那么添加的元素需要与其中已有的值交错)。这些容器的开销可能高于以任意顺序插入到集合中的开销:您必须对其进行测试。
不幸的是,我相信您仅限于线性O(N)
解决方案,因为所有并集都是两个集合中元素的组合。
template<typename S>
S union_sets(const S& s1, const S& s2)
{
S result = s1;
result.insert(s2.cbegin(), s2.cend());
return result;
}
首先找到最小集合的并集。也就是说,按集合长度对集合进行排序,计算两个最小集合的并集,删除这些集合,根据其大小将并集插入到集合列表中。
如果你测量了两个集合的相似程度,那么你最好先找到最相似集合的并集。这是更倾向于尽早消除重复项的工会操作。
编辑:对于两个集合之间的每个并集操作 - 将较小的集合合并到较大的集合中。
我假设快速你的意思是快速实现。
然后: 标准::set_union (*)
两组示例:
#include <set>
#include <algorithm>
#include <iterator>
using namespace std;
int main () {
set<pair<int,int> > a, b, uni;
set_union (a.begin(), a.end(),
b.begin(), b.end(),
inserter(uni, uni.begin()));
}
对于 n 个集合,手写它可能是最易于维护的解决方案:
#include <set>
#include <vector>
using namespace std;
int main () {
vector<set<pair<int,int>>> sets;
set<pair<int,int>> uni;
for (const auto &s : sets)
for (const auto &elem : s)
uni.insert (elem);
}
尽管一般来说,人们应该更喜欢标准算法并从其质量实现中获利。
如果您所说的快速是指性能,我们无能为力,因为我们没有要求。对于不同的情况,不同的方法可能会产生不同的结果。
(*) 注意:该网站有时因为与标准相比不是 100% 准确而皱眉
尝试标头算法中的set_union。
为了节省内存分配并改善局部性,最好使用单个vector<T>
作为工作内存。
构造一个vector<T>
并保留所有 s 中的元素总数(计算重复项)。 然后,从空范围[v.begin(), v.begin())
开始,通过附加每个集合的内容,合并和统一,将其扩展到类似集合(唯一,排序)的范围:
vector<T> v;
v.reserve(<total size>);
for (set<T> &s: sets) {
auto middle = v.insert(v.end(), s.begin(), s.end());
inplace_merge(v.begin(), middle, v.end());
v.erase(v.unique(v.begin(), v.end()), v.end());
}
使用 std::set_union递归或简单地将所有集合插入到结果集中(重复项由集合消除)。如果项目数量非常少,您可以尝试将其全部插入到向量中,对其进行排序并在向量上使用 std::unique。
- 处理多个异常集合的C++方法
- 保留计时器集合(对象与指针)的最佳方法
- 查询数据库以在 C++ 中创建自定义类集合的最佳方法
- 为什么以相同的数量插入到集合中,基于不同的方法具有不同的运行时间?
- 有没有一种单行方法来调用集合上的 lambda 函数
- 对集合调用成员方法
- 在C 中,有一种惯用方法来防止运行一系列动作的情况导致该集合被突变
- 在集合方法中传递 get 方法
- C++集合方法:函数'setCost'不可行:'this'参数的类型'const value_type'
- 方法插入到任何stl集合中
- 模板集合的不同排序方法
- 位掩码:通过集合方法设置对象的不同状态
- 从集合中随机给定整数 0、1 和 2 时获取整数 0、1 和 2 的快速方法
- 支持多线程方法来构建数组中所有元素的集合吗
- 在 c++ 中搜索集合的最有效方法是什么
- 找到集合并集的最快方法
- STL 集合的插入方法是否复制传递对象的值?
- 对基于地图C++集合重新排序的有效方法
- 如何使用提升 lambda 对集合中的每个元素调用方法?
- 迭代集合并集的干净方法