关于正则表达式:我们什么时候实际使用Trie?

When do we actually use a Trie?

我开始读关于特里亚的书。我还从这里的朋友那里得到了一些参考资料:关于trie的教程

我不清楚以下几点:似乎继续使用trie-one假定所有将作为搜索空间的输入字符串以及用于构建trie的输入字符串在不同的单词边界中是分开的。例如,我看到的所有示例教程都使用输入,例如:

1
S={ball, bid, byte, car, cat, mac, map etc...}

然后我们用S构建trie并进行搜索(非常快)我的问题是:我们是如何以S结尾的?我的意思是,在开始阅读关于尝试的文章之前,我认为S是一个任意长的文本,例如Shakespeare段。

然后使用trie,我们可以很快找到东西。但似乎情况并非如此。

这里假设的输入通道(例如Shakespeare的输入通道)是预先处理的,首先提取所有单词以得到S吗?

所以,如果有人想搜索模式(就像你在谷歌上搜索并看到所有页面在你的搜索查询中也有空格时一样),trie是不合适的?何时才能知道trie是否是我们实际可以使用的数据结构?


如果你有一个固定的字典,你想快速查找,尝试是有用的。与哈希表相比,大型字典可能需要更少的存储空间,但查找起来可能需要更长的时间。我使用它的一个例子是将URL映射到Web服务器上的操作,如果存在基于前缀的功能继承的话。在这里,向下递归trie可以适当地查找需要为特定URL调用的所有方法。它还可以有效地存储字典。

对于文本搜索,您通常会使用带权重的词汇表的标记向量(可能基于出现频率)来表示文档,然后根据标记向量进行搜索,以根据特定的搜索向量对文档进行排名。有许多标准库可以做到这一点,我建议您使用这些库,而不是自己编写库-尤其是删除停止词、处理同义词和词干。


尝试有多种方式。典型的例子是一个查找,比如您所展示的查找。但是,也可以使用尝试来完全索引完整的文本。要么使用Ukkonen后缀树算法生成后缀trie,要么通过存储后缀(比Ukkonens算法慢得多,但也更简单)来明确构造后缀trie。因为这是预处理,所以只有在速度不是那么重要的时候才需要进行预处理。

为此,你只需把你的文本,插入全文,然后第一个字母的印章,插入结果文本,第二个字母的印章,插入…

因此,如果我们有文本"the text",我们将插入以下集合:

1
{"The Text","he Text","e Text"," Text","Text","ext","xt","t"}

在生成的后缀trie中,我们可以轻松地搜索任何类型的前缀。另外,这也是节省空间的,因为我们不需要存储整个字符串,因为公共前缀只存储一次。

如果您需要有效地存储更长的字符串空间,那么最好不仅将前缀存储在一起,还将后缀存储在一起。在这种情况下,您可以建立一个有向无环词图(DAWG),这在概念上非常类似于trie。

所以从这个意义上讲,trie允许查找任意子字符串,包括部分单词。如果您只对存储单词感兴趣,则应使用不同的数据结构,例如倒排列表(如果顺序很重要)或基于向量空间的检索算法(如果顺序无关紧要)。


如其他示例所述,trie非常有用,因为它提供了快速的字符串查找(或者更一般地说,查找任何序列)。我在哪里使用过尝试的一些示例:

  • 我对这个问题的答案使用了一个(稍微修改过的)trie来匹配句子:它是基于单词序列而不是字符序列的trie。(对该问题的其他答案可能更清楚地说明了trie的作用。)
  • 我也在一个游戏中使用了一个trie,这个游戏有很多有名字的房间(总数和名字是在运行时定义的),每个名字都必须是唯一的,并且必须能够快速搜索一个有名字的房间。也可以使用哈希表,但在某些方面,trie更容易实现,在使用字符串时速度更快。(我的trie实现最终是大约50行C。)

trie标签可能还有更多的例子。


我们可以使用尝试在线性时间内搜索子字符串,而不必每次预处理字符串。您可以获得关于后缀树生成的最佳教程。@纯英语中的Ukkonen后缀树算法?