C++ 从一组集合中找到集合子集的最佳方法

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查询函数,那么它们可能会尽可能

首先,很抱歉标题模棱两可

假设我有以下一组集合:

第一组 第2组 对于
组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)的子集

因此,在您的示例中,它应该只返回m2,这是s1的子集?@crush是的,我已经为我的示例发布了解决方案。我不确定我是否理解。你是说m1是s1的子集,还是反过来说?似乎s1是m1的一个子集。但是s2是m3的一个子集,那么s2->m3不是吗?对不起,如果我误解了这一点。@Patrick87对不起,我错了。它应该是m2,而不是m1。更正。你能使用排序列表和二进制搜索吗?如果你要否决我的投票,那很好,但至少给出一些这样做的理由。我写的错了吗?嗯。。。我们在这里被一个连续的驱动器所困扰。有些人就是不愿意表现得很好:|@BrankoDimitrijevic:我曾经回答过一个问题,这个问题也发生过。大多数答案都被否决了,没有任何解释。。。两次。看起来有点奇怪,但大多数人玩这个“游戏”相当不错。这是一个很好的社区。我甚至不知道std::includes()的存在。我想我现在需要修改我的回答。。。
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 */ }
    }
  }
}