Trie vs.后缀树与后缀数组

时间:2010-03-21 15:26:09

标签: java arrays data-structures trie

哪种结构提供最佳性能结果; trie(前缀树),后缀树或后缀数组?还有其他类似的结构吗?这些结构有哪些优秀的Java实现?

编辑:在这种情况下,我想在一个大的名字字典和一大组自然语言文本之间进行字符串匹配,以便识别文本上字典的名称。

7 个答案:

答案 0 :(得分:56)

trie是第一个发现的数据结构。

后缀树是对trie的改进(它具有允许线性错误搜索的后缀链接,后缀树修剪了trie的不必要分支,因此它不需要那么多空间)。

后缀数组是基于后缀树的精简数据结构(没有后缀链接(慢速错误匹配),但模式匹配非常快)。

trie不适合现实世界使用,因为它占用了太多空间。

后缀树比trie更轻更快,用于索引DNA或优化一些大型网络搜索引擎。

后缀数组在某些模式搜索中比后缀树慢,但使用的空间更少,并且比后缀树使用得更广泛。

在同一系列的数据结构中:

还有其他实现,CST是后缀树的一个实现,它使用后缀数组和一些额外的数据结构来获得一些后缀树搜索功能。

FCST进一步采用它,它实现了带后缀数组的采样后缀树。

DFCST是FCST的动态版本。

展开:

两个重要因素是空间使用和操作执行时间。你可能会认为,对于现代机器而言,这是不相关的,但索引单个人的DNA将需要40千兆字节的内存(使用未压缩和未优化的后缀树)。要在这么多数据上构建其中一个索引可能需要数天时间。想象一下谷歌,它有很多可搜索的数据,他们需要一个大的索引覆盖所有的网络数据,并且他们不会在每次有人建立网页时改变它。他们有某种形式的缓存。然而,主要指数可能是静态的。每隔几周左右,他们会收集所有新的网站和数据,并建立一个新的索引,在新的完成时替换旧的索引。我不知道他们使用哪种算法进行索引,但它可能是一个后缀数组,在分区数据库上有后缀树属性。

CST使用8千兆字节,但后缀树操作速度大大降低。

后缀数组可以在700 megas到2 Gigas中完成相同的操作。但是,您不会在带有后缀数组的DNA中发现遗传错误(意思是:使用通配符搜索模式要慢得多)。

FCST(完全压缩的后缀树)可以创建800到1.5千兆的后缀树。对CST的速度恶化相当小。

DFCST使用比FCST多20%的空间,并且失去了FCST静态实现的速度(但动态索引非常重要)。

后缀树的可行(空间明智)实现并不多,因为很难使操作速度提升来补偿数据结构的RAM空间成本。

这就是说,后缀树对于带错误的模式匹配有非常有趣的搜索结果。 aho corasick不是那么快(虽然对于某些操作几乎同样快,而不是错误匹配)并且boyer moore留在尘埃中。

答案 1 :(得分:4)

您打算做什么操作? libdivsufsort曾经是C语言中最好的后缀数组实现。

答案 2 :(得分:2)

使用后缀树你可以在O(n + m + k)时间写一些与你的字典匹配的东西,其中n是你字典中的字母,m是你文字中的字母,k是匹配的数量。尝试要慢得多。我不确定后缀阵列是什么,所以我不能对此发表评论。

也就是说,这对代码来说并不重要,我也不会知道任何提供必要功能的Java库。

答案 3 :(得分:1)

  

编辑:在这种情况下,我想在一个大的名字字典和一大组字符串之间进行字符串匹配   自然语言文本,以便在文本上识别字典的名称。

这听起来像是Aho-Corasick algorithm的应用程序:从字典中构造一个自动机(在线性时间内),然后可以用来查找多个文本中任何字典单词的所有出现(也在线性时间)。

these lecture notes中的描述,从维基百科页面的“外部链接”部分链接,比页面本身的描述更容易阅读。)

答案 4 :(得分:1)

Trie vs Suffix tree

两种数据结构都能确保快速查找,搜索时间与查询字的长度成正比,复杂时间为O(m),其中m是查询字的长度。

这意味着如果我们的查询字有10个字符,那么我们最多需要10个步骤才能找到它。

Trie:用于存储字符串的树,其中每个公共前缀都有一个节点。字符串存储在额外的叶节点中。

suffix tree:对应于给定字符串后缀的trie的紧凑表示,其中所有带有一个子节点的节点都与其父节点合并。

def来自: 算法与数据结构词典

通常Trie用于索引字典单词(词典)或任何字符串集 例子D = {abcd,abcdd,bxcdf,.....,zzzz}

后缀树,用于通过使用相同的数据结构索引文本" Trie"在我们的文本的所有后缀上 T = abcdabcg 所有后缀T = {abcdabcg,abcdabc,abcdab,abcda,abcd,abc,ab,a}

现在它看起来像一组字符串。 我们在这组字符串上构建了一个Trie(所有后缀都为T)。

两种数据结构的构造都是线性的,它在时间和空间上都需要O(n)。

如果是dicionary(一组字符串):n =所有单词的字符总和。 在文本中:n =文本的长度。

后缀数组:是一种在压缩sapce中表示后缀树的技术,它是一个字符串后缀的所有起始位置的数组。

它在搜索时间内比后缀树慢。

有关更多信息,请访问维基百科,有一篇很好的文章谈论这个主题。

答案 5 :(得分:1)

我更喜欢后缀自动机。 您可以通过我的网站找到更多详细信息: http://www.fogsail.net/2019/03/06/20190306/

enter image description here

首先,如果使用普通构造,则需要O(n ^ 2)来遍历所有后缀

我们使用基数排序对后缀Array按第一个字符进行排序。

但是,如果我们对第一个字符进行排序,则可以使用该信息。

图像显示细节(忽略中文)

我们通过第一键对数组进行排序,结果以红色矩形表示

,.....--->,....

enter image description here

for item in matches.HomeTeam:
    matches = matches.replace(to_replace = matches.HomeTeam[item], value=teams.TeamName[item])

答案 6 :(得分:0)

This诱导排序算法(称为sais)的实现具有用于构造后缀数组的Java版本。