以下是我想对假设的集合数据结构执行的操作,该集合数据结构将集合作为其元素:
所讨论的所有集合都是已知有限集的子集,比如{0..10 ^ 4}。
有没有办法有效地做到这一点?
答案 0 :(得分:1)
所讨论的所有集合都是已知有限集的子集,比如{0..10 ^ 4}。
我们称之为N = 10 ^ 4。这相当小,这将证明是有用的。假设你有S套。
'逻辑'这意味着你有一个N * S矩阵。
您将拥有一组套装。这个主要结构中有S套。
10 ^ 4足够小,您可以维护辅助数据结构,该结构为每个N值存储它所在的集列表。结构有点像主结构的转置。这可以是长度为N的向量,允许持续时间查找以查找特定值所在的集合列表。
现在,当您添加一个新集合时,可以使用此二级结构来查找其每个值所在的其他集合。例如,我们添加一个值为2,5,10的新集合
new_set = {2,5,10}
二级结构告诉我们他们在哪些集合中:
2 : {A,B,D}
5 : {B,D}
10 : {B}
我们可以对这三个列表进行合并和排序,以获得ABBBDD
,它不仅告诉我们它与哪些集重叠,还告诉我们重叠的大小。 B共享三个节点,这意味着我们的新集合是B的子集,或者等于B.我们用A共享1个节点,用D共享2个节点。如果事实证明A的总大小是1,那么我们现在知道A是我们新集合的一个子集。
答案 1 :(得分:1)
以下是有关此问题的最新文章:http://research.google.com/pubs/pub36974.html
简而言之,在最坏的情况下,你不能比二次时间好得多;但是在实践中有一些技巧可以加速它。
答案 2 :(得分:0)
枚举集合中的集很容易,O(n)。但是,检查新候选人是否是所有现有集合的子集将会有点昂贵。众所周知的算法用于测试一组是否是另一组的子集,如此简单
for each subset s in S
for each candidate set C
test of C is a subset of s
if it is, break
if never found, add C to S.
那将是O(n ^ 2 lg n)。这算是“有效”吗?
答案 3 :(得分:0)
为所有存储的集维护一个bloom过滤器。为要插入的集生成bloom过滤器。如果你用另一个集合的布隆过滤器按位并且要插入的集合的过滤器(调用这个X),然后得到值X,那么你要插入的集合可能是一个子集(可能是误报,你需要检查在这一点上的缓慢方式)。否则它肯定不会,你可以尝试另一个。
构建布隆过滤器时,有许多可调参数,可让您在空间效率和误报概率之间进行权衡。
答案 4 :(得分:0)
对于空间效率,您可以使用位集来表示已知有限集的每个子集。还有表示稀疏比特集的方法(参见例如this Java sample),以进一步节省空间。
整体结构可以是一组位集。在Java中,BitSet
没有子集测试方法,但我认为扩展BitSet
以包含有效的子集测试方法并不太难。 (这将避免测试要添加的候选者是否等于其与任何现有子集的交集的令人讨厌的任务。)
答案 5 :(得分:0)
使用某种树形结构。
EG。将已排序的现有集存储在Trie中。如果通向该节点的路径是现有集合
,则每个节点都保持一个Flag1检查给定集合是否是现有集合的超集:
def issuperset(node, set[N], setc, N): if node.is_set: return True for j = setc:N if set[j] is a child of node: if issuperset(node.child[set[j]], set, j+1, N): return True return False
2删除给定集的所有超集
def remsuperset(node, set[N], setc, N): if setc == N+1: remove_all_sets_on_or_below_this_node(node) return for ch in node.child: if ch< set[setc]: remsuperset(node.child[ch], set, setc, N) elif ch == set[setc]: remsuperset(node.child[ch], set, setc+1, N)
3对于枚举集只是遍历树,打印路径是is_set标志为True