在多个集合上测试IsSubset关系

时间:2012-03-11 17:00:20

标签: c# .net performance set

在遍历图表时,我需要测试弧是否允许访问通过已经行进的弧线无法访问的其他节点。所以实际上我想测试所讨论的弧的后继者是否是已经访问过的弧的组合后继者的子集。

这里有一些(不太理想的)代码来说明所需的操作:

    public static bool ReachesAdditionalSuccs(
                    ISet<int>   additionalSuccCandidates,
                    ISet<int>[] succsAlreadyReachable)
    {
        ISet<int> curCombinedSuccsReachable = new HashSet<int>();
        foreach (ISet<int> set in succsAlreadyReachable)
            curCombinedSuccsReachable.UnionWith(set);
        return (!additionalSuccCandidates.IsSubsetOf(curCombinedSuccsReachable));
    }

由于我需要在扩展和搜索时间动态游戏树的过程中执行此操作,因为内存限制,我无法预先构建后续组合。也没有将节点标记为已访问的选项。我只能预先建立直接​​的后继者来加速某些事情。

我现在想知道最快的方法是什么。在上面的代码中,我暂时在新的Hashset-object中构建一个组合集。这是非常耗时的,当然不是最聪明的方式。我想到的一种不同的方法是循环遍历所有节点,并使用Hashsets对所有零件集进行手动测试。但这可能也不是最好的方式......

我想到的最后一件事是使用SortedSets,因为这些应该很容易组合(在O(n)中,就像合并排序一样),而isSubset操作也有O(n) - 复杂性。有没有一种聪明的方法来实现这一点而不用自己编码,所以甚至可能在Framwork中内置?或者甚至有更快的方法?

1 个答案:

答案 0 :(得分:1)

我认为你可以为套装做的最佳选择是逐个过滤数字,但直到你找到一个未包含在任何其他套装中的数字并在那里停止。用Linq表示:

public static bool ReachesAdditionalSuccs(
                    ISet<int> additionalSuccCandidates,
                    ISet<int>[] succsAlreadyReachable)
{
    return additionalSuccCandidates.Where(x => !succsAlreadyReachable.Any(set => set.Contains(x)))
                                   .Any();
}

最坏情况的总体努力(已经包含在集合中的所有数字)将为O(mn) - 假设设置查找时间为O(1) - 其中m是{{1}中的数字1}}和additionalSuccCandidatesn中的集合数。

进一步优化将使用succsAlreadyReachable - 您可以使用最小值和最大值来过滤掉您首先不必检查的集合:

SortedSets