繁体   English   中英

等效子树

[英]Equivalent subtree

我有两棵树。 树节点定义为

class Node{
  String treeId; 
  String type;       //Each node has type which has fixed value. For example, its color: RED, BLANK, GREEN
  Set<Node> children;
  String ref;        //The ref is a string and allowed value are "0", "1",..."10". The value is null if it is not leaf. 
};

对于叶子,子集为空。

我想知道是否已经完成了一些有效的工作,如何为两个给定的树识别等效的子树。 等效定义为:

1) Both subtree leaves are setsets leaves of original tree. 
2) Both subtrees leaves have same ref value. 
3) for non-leaves node, the equivalent refers to both node have same type and equivalent children. 

谢谢。 如果有一些Java库可以解决此问题,那就更好了。


输入应该是两个树的根,而输出是作为等效子树的根的Node。 树的高度为100〜,并且有500多个节点。


我现在所做的是为类Node添加了一个新字段。

class Cache{
   Map<String, Set<String>> map = new LinkedHashMap<String, Set<Str>>();
}

映射的键是节点ID,而值是该节点ID的此节点可以到达的引用集。 初始化节点时启动的缓存。

在isEquivalent比较阶段,检查两个根的引用集之间是否存在重叠。 如果没有返回false。

我认为这可以帮助减少比较空间的数量。

我不确定1) Both subtree leaves are leaves of original tree. 要求似乎与how to identify equivalent substree for two given tree.相冲突how to identify equivalent substree for two given tree. 否则下面的递归方法应该能够覆盖其他两个条件。 可以实现haveSameOriginalTree(r1, r2)方法来满足我无法理解的第一个条件。 r1r2是需要检查是否相等的两个子树的根。

bool areEquivalent(Node r1, Node r2)
{
    if(r1.children == null && r2.children == null)
    {
        return (haveSameOriginalTree(r1, r2) && (r1.ref == r2.ref));
    }
    if((r1.children == null && r2.children != null) || (r1.children != null && r2.children == null))
    {
        return false;
    }
    // if here then both must be non-leaf nodes
    if(r1.type != r2.type)
    {
        return false;
    }
    if(r1.children.getCount() != r2.children.getCount()) // not sure of correct syntax for Java Sets
    {
        return false;
    }
    for(int i=0; i<r1.children.getCount(); i++)
    {
        if(!areEquivalent(r1.children[i], r2.children[i])) // again please correct the syntax for Sets
        {
            return false;
        }
    }

    return true;
}

让我知道你的想法。

更新资料

这是上述解决方案的迭代版本。 它使用分配在堆上的堆栈数据结构,而不是推入函数的调用堆栈,因此与递归没有太大区别,但仍然更好。 另外,由于我们仅保留对Node的引用(而不是复制整个对象),因此如果我们已经将原始树加载到内存中,那么这不应该是那么多的额外内存开销。

bool areEquivalent(Node r1, Node r2)
{
    Stack<Node> s1 = new Stack<Node>();
    Stack<Node> s2 = new Stack<Node>();
    Node n1, n2;

    s1.Push(r1);
    s2.Push(r2);
    while(true) // Need a better check
    {
        if(s1.getCount() != s2.getCount())
        {
            return false;
        }
        if(s1.getCount() == 0) // if both stacks are empty then we've traversed both trees without failure.
        {
            return true;
        }
        n1 = s1.Pop();
        n2 = s2.Pop();
        if(!areEquivalentNodes(n1, n2))
        {
            return false;
        }
        foreach(Node child in n1.children)
        {
            s1.Push(child);
        }
        foreach(Node child in n2.children)
        {
            s2.Push(child);
        }
    }
}

// only checks the two nodes are equivalent. their childrens' equivalence will be handled by other calls to this method.
bool areEquivalentNodes(Node n1, Node n2)
{
    if(n1.children.getCount() != n2.children.getCount())
    {
        return false;
    }
    if(n1.children.getCount() == 0) // if both are leaf nodes...
    {
        if(n1.ref != n2.ref)
        {
            return false;
        }
    }
    else // both are non-leaf
    {
        if(n1.type != n2.type)
        {
            return false;
        }
        // the condition that children of non-leaf nodes be equivalent will be covered by subsequent calls this method...
    }

    return true;
}

请注意,这两个解决方案,希望children在同一顺序两个等价节点。 如果未订购children则在调用上述代码之前,我们需要对它们进行排序。

让我知道这是否更好。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM