我一直在寻找有关后缀树的教程。在SO中,我发现了2篇关于理解后缀树的帖子:1,2。
但我不能说我理解如何建立一个,哎呀。在Skiena的书“算法设计手册”中,他说:
由于线性时间后缀树构造算法非常重要, 我建议使用现有的实现。
那么,后缀树的在线构造算法是如此难以实现吗?任何人都可以帮我理解它吗?
无论如何,切入追逐,除了构造之外,还有一件我对后缀树不了解的事情。因为后缀树中的边只是一对整数(右?),指定了子串的起始和结束位置,那么如果我想在这个后缀树中搜索字符串x
,我应该怎么做呢?取消引用后缀树中的那些整数,然后将它们与x
逐个进行比较?不可能这样。
答案 0 :(得分:21)
首先,构建后缀树的方法有很多种。 Weiner(1973)的原始O(n)方法,由McCreight(1976)改进的方法,Ukkonen最着名的方法(1991/1992),以及一些进一步的改进,主要与实施和储存有关效率考虑。其中最值得注意的可能是Giegerich和Kurtz的Efficient implementation of lazy suffix trees。
此外,由于后缀数组的直接构造在2003年的O(n)时间内已经成为可能(例如使用Skew algorithm,但也有其他的),并且因为
有充分研究的方法后缀数组通常比后缀树更受欢迎。因此,如果您的目的是为特定目的构建高度优化的实现,您可能需要研究后缀数组构造算法。
但是,如果您对后缀树构造感兴趣,特别是Ukkonen算法,我建议您仔细查看您已经提到过的this SO post中的说明,然后我们尝试一起改进这种描述。这肯定远非完全直观的解释。
回答有关如何将输入字符串与边缘标签进行比较的问题:出于效率原因,在构造和查找过程中,每个边缘标签的初始字符 strong>通常都是存储在节点中。但是其余部分必须在主文本字符串中查找,就像你说的那样,这确实会引起问题,特别是当字符串太大而不能容易地保存在内存中时。 (加上事实,就像任何树的直接实现一样,后缀树是一个包含大量指针的数据结构,它消耗大量内存并且难以维护引用的位置和受益于内存缓存)是后缀树难以处理的主要原因之一,例如倒排索引。
答案 1 :(得分:5)
如果你将后缀数组与 lcp表和子表结合起来,当然你应该这样做,你基本上会得到一个后缀树。这一点在文章中提出:Kim,Park和Kim的Linearized Suffix Trees。 lcp表启用了一个相当笨拙的自下而上遍历,子表可以轻松遍历任何一种类型。所以关于后缀树的故事使用引起参考问题局部性的指针在我看来是过时的信息。因此,只要使用底层后缀数组实现树,后缀树就是“正确而简单的方法”。
Kim,Park和Kim撰写的论文描述了Abouelhoda等人误导性标题文章中的方法变体:用后缀数组替换后缀树。 Kim等人的文章认为这是后缀树的实现,而不是替换。此外,Kim等人更简单直观地描述了Abouelhoda等人的构造细节。
,
答案 2 :(得分:0)
这里有一个Ukkonen后缀树的线性构造(加上后缀数组,lcp数组)的实现:http://code.google.com/p/text-indexing/。与suffixtree.js一起提供的可视化可能会有所帮助