C++ 从一组集合中找到集合子集的最佳方法
首先,很抱歉标题模棱两可 假设我有以下一组集合: 第一组 第2组 对于C++ 从一组集合中找到集合子集的最佳方法,c++,algorithm,set,subset,C++,Algorithm,Set,Subset,首先,很抱歉标题模棱两可 假设我有以下一组集合: 第一组 第2组 对于组1中的每个集合,调用集合s,我需要找到组2中的集合-调用它m-这样m就是s的子集 以我为例,答案是: s1 -> m2 s2 -> nothing 现在,我将值存储在std:set中,但如果需要,我可以更改它。此外,集合可能会变大,因此算法需要高效。现在我有一个蛮力的方法,我并不完全满意 有什么建议吗?你没有具体说明你的方法有多残忍。只要您在std::namespace中使用set查询函数,那么它们可能会尽可能
组1
中的每个集合,调用集合s
,我需要找到组2
中的集合-调用它m
-这样m
就是s
的子集
以我为例,答案是:
s1 -> m2
s2 -> nothing
现在,我将值存储在std:set
中,但如果需要,我可以更改它。此外,集合可能会变大,因此算法需要高效。现在我有一个蛮力的方法,我并不完全满意
有什么建议吗?你没有具体说明你的方法有多残忍。只要您在std::namespace中使用set查询函数,那么它们可能会尽可能地高效。 例如,测试集合_交点(s1.begin()、s2.end()、m1.begin()、m1.end())是否等于m1 您可以更高效,因为您不需要匹配元素的副本,只需要知道它们都出现了。这可以通过复制set_intersection的代码来实现,但将实现更改为只计算匹配元素的数量,而不是将它们复制出去。然后,如果计数与m的大小相同,则有一个匹配项
至于容器,对于大型集合,我通常更喜欢排序的deque而不是set。内存在堆上的分布要小得多,这有助于缓存。它还避免了底层树的开销。当容器创建一次,但被搜索多次时,这尤其有用。第一步是根据基数(即大小)对组1进行排序。那么算法的顺序是:
foreach std::set M in "Group 2" {
foreach std::set S in "Group 1" and S.size()>=M.size() { // replace with binary search
if ( std::includes(S.begin(),S.end(),M.begin(),M.end()) )
{ /* M is a subset of S */ }
}
}
}
这应该具有时间复杂度O(MSR),其中M是“组2”中集合的#,S是“组1”中集合的#,R是“组1”中最大集合的大小
编辑:我突然想到,使用
S.find()
可能比调用std::includes()
(按顺序迭代)更有效,但我认为只有当M.size()比S.size()小得多时才是这样——O(M+S)比O(MlogS).您的设置是经常修改还是只读/大部分
- 如果频繁修改,
在修改和排序性能之间取得了良好的平衡std::set
- 如果是只读或多读,可以使用排序的
。排序很昂贵,但实际上比在std::vector
中构建一个完整的树便宜,因此如果很少这样做,性能会更好std::set
创建已排序的容器(无论是“自动排序”的
std::set
还是手动排序的std::vector
),都可以使用std::includes
测试子集。顺便说一句,如果您需要找到合适的子集,您可以在之后比较元素计数。您可以尝试类似的方法。
步骤:
- 创建包含两个组中所有对象的数组
- 转换位数组中的每个s和m,其中数组(i)=1(如果集合包含对象(i),否则为0
- 如果m(k)和s(j)=m(k),m(k)是s(j)的子集
s1 -> m2
s2 -> nothing
foreach std::set M in "Group 2" {
foreach std::set S in "Group 1" and S.size()>=M.size() { // replace with binary search
if ( std::includes(S.begin(),S.end(),M.begin(),M.end()) )
{ /* M is a subset of S */ }
}
}
}