我有一组由整数对组成的集合,例如 set<pair<int,int> > x1, x2, ... xn
(其中 n 可以在 2 到 20 之间)。最快的方法是找到这些集合的并集?
抱歉如果一开始没有表述清楚,我指的是性能上的快速度,内存分配不是问题。
我有一组由整数对组成的集合,例如 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
时,为了让添加的元素按递增顺序排序,每次调用函数都需要创建一个新的空容器(因为如果容器不为空,则添加的元素需要与已有值交错)。这些容器的开销可能会比随意插入 set 中的开销更高:你需要进行测试。
x1
和x2
已经是排序好的范围。 - ecatmur首先找出最小的集合的并集。即根据集合长度对集合进行排序,计算最小的两个集合的并集,删除这些集合,将并集按大小插入到集合列表中。
如果您有两个集合之间相似程度的测量值,则最好首先找到最相似的集合的并集。也就是说,优先选择消除重复项的并集操作。
编辑:对于每个两个集合之间的并集操作-将较小的集合合并到较大的集合中。
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
的2*(count1+count2)-1
要多得多。@phresnel的第一个解决方案应该更快。 - Tillset::insert
方法。因此,它与此处的解决方案具有相同的大O复杂度 - 顺便说一下,这里声明的复杂度不是线性的,而是O(N * log(N))
。但是,如果您让“插入器”将结果插入到list
而不是set
中,则phresnel的解决方案可以是线性的。但我不确定这是否符合原始问题的要求。 - mastov#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);
}
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());
}
sizeof<pair<int,int> >
;-p 我猜测是8个字节。集合数量为2-20。其余内容不在问题中。 - Steve Jessop