我有一些树的集合,它们的节点被标记了(但不是唯一的)。具体来说,这些树来自一组经过解析的句子(请参阅http://en.wikipedia.org/wiki/Treebank)。我希望从集合中提取最常见的子树- 性能(还)不是问题。我将感谢算法(理想情况下为Java)或指向可用于树库的工具的指针。请注意,子节点的顺序很重要。
编辑 @mjv。我们正在使用一种风格化语言的有限域(化学)中工作,因此树木的多样性不是很大-可能类似于儿童读者。“猫坐在垫子上”的简单树。
<sentence> <nounPhrase> <article/> <noun/> </nounPhrase> <verbPhrase> <verb/> <prepositionPhrase> <preposition/> <nounPhrase> <article/> <noun/> </nounPhrase> </prepositionPhrase> </verbPhrase> </sentence>
这里的句子包含两个相同的词性子树(实际标记“ cat”。“ mat”在匹配中并不重要)。因此,该算法将需要检测到这一点。请注意,并非所有名词短语都相同-“大黑猫”可能是:
<nounPhrase> <article/> <adjective/> <adjective/> <noun/> </nounPhrase>
句子的长度会更长-在15到30个节点之间。我希望从1000棵树中得到有用的结果。如果此过程不超过一天左右,则可以接受。
显然,树越短越频繁,因此名词短语将很常见。
编辑 如果这将通过展平树来解决,那么我认为它将与最长公共子字符串有关,而不是与最长公共序列有关。但是请注意,我不一定只想要最长的- 我想要列出所有足够长的列表以使它们“有趣”(标准待定)。
在集合中查找最频繁的子树,创建子树的紧凑形式,然后迭代每个子树并使用哈希集计算它们的出现次数。30个节点太大了,无法实现完美的哈希- 每个节点只有大约1位,您需要大量的资源来表明它是同级还是子级。
问题不在于LCS-最常见的序列与最长的常见子序列无关。最频繁的子树是出现次数最多的子树。
对于N个长度为L的树,在最坏的情况下应该是O(NL ^ 2)(假设测试包含L个节点的子树的相等性为O(L))。