对于我目前正在进行的研究项目,我需要完成的任务之一如下:给定一个有根,标记的有向树,我需要找到所有子树重复< / em>在这棵树中;换句话说,给定所有树的子树(至少有一个节点),我需要将所有子树组合在一起,使用相同的标签集和结构体。例如,让我们说我们有以下树,根A:
A / \ / \ B A |\ |\ C C B A | C
在这种情况下,有几个重复的子树模式,例如以下......
模式1(发生3次):
A | B | C
模式2(发生3次):
A |\ B A | C
模式3(发生2次):
A | B
...依此类推。仅供参考,&#34;根,标记,指导树&#34;我关心的是从JavaScript代码生成的抽象语法树(AST)。
现在,我已经提出了自己的算法来查找所有子树重复。当JavaScript代码非常小(因为AST也很小)时,它运行良好,并且算法立即完成。但是当我将JavaScript代码的行数增加到10行时,算法在一个多小时后甚至没有完成执行! 所以我的问题是,是否有人知道更有效和可扩展的算法来查找所有子树重复?仅供参考,我实施此算法的语言也是JavaScript。
供您参考,我当前的算法基本上是一个递归算法,它对树进行后序遍历(在此上下文中的后序表示,&#34;首先访问此节点的子节点,然后访问节点&#34)。在每个节点访问时,算法通过遍历算法中先前确定的子节点的子树的每个组合,找到以该节点为根的所有子树;对于根据该节点找到的每个子树,该算法基于三个方面计算哈希值:(1)节点的标签; (2)在此子树中出现的节点的子节点数; (3)当前在该子树中出现的子树的子树的哈希值。然后将散列到相同值的子树放在同一组中。 (散列函数的潜在不准确性也需要解决,但我还没有达到那个部分......)。
答案 0 :(得分:1)
您正尝试在抽象语法树中重新发明克隆检测。是的,匹配树的基本思想是使用散列将它们放入“可能等效”的桶中,然后检查那些可能等效于实际等效的桶。这是一种经典的编译器算法,用于支持查找公共子表达式。
如果等效子树的数量与散列桶的数量相比较小,并且您的散列算法很不错,那么这在树的大小上基本上是线性的。 (坏散列或一个桶可以使其为N ^ 2)。
我不太了解你的算法;听起来你基本上就是这么做的。如果没有更精确的表征(例如,伪代码),就很难看出出了什么问题。
研究工作做得很久。请参阅我的CloneDR技术论文,这是一个执行此操作的工具:http://www.semanticdesigns.com/Company/Publications/ICSM98.pdf(您可以在同一站点找到JavaScript CloneDR)。
找到几乎相同的子树有一个更难的问题,本文也讨论了这些问题。那是迄今为止最有趣的部分, 并且要快得多。
我们经常在数百万行系统上运行CloneDR。在这种规模下,它需要花费数小时才能完成并行的编译到本机代码实现。 JavaScript可能不是你的朋友。