Scrabble单词查找器:构建trie树,存储trie树,使用trie树?

7
我想做什么:
  • 开发一款移动Web应用程序,用户可以在玩Scrabble时获得帮助找到单词
  • 用户通过输入任意数量的字母和0个或多个通配符来获取单词建议
我是如何尝试实现这个目标的:
  • 使用包含超过400k个单词的MySQL数据库
  • 使用ASP.NET和C#作为服务器端编程语言
  • 使用HTML5、CSS和Javascript
我的当前计划:
  • 使用数据库中的所有单词构建Trie,以便根据用户输入的字母/通配符快速准确地搜索单词
然而,如果你不能执行这个计划,那么这就没有用了。以下是我需要帮助的部分:
  • 如何从数据库中构建Trie?(更新:我想使用已经存在于我的数据库中的单词生成Trie,之后我将不再使用数据库进行单词匹配)
  • 如何存储Trie以便快速轻松地访问?(更新:以便我可以删除我的数据库)
  • 如何使用C#根据字母和通配符使用Trie搜索单词?
最后:
非常感谢您的帮助,我仍然是C#和MySQL的初学者,请多多关照。
非常感谢!

2
请注意,这是对https://dev59.com/8lvUa4cB1Zd3GeqPr0RE的后续问题。 - Eric Lippert
1个回答

17

首先,让我们来看看问题的限制条件。您希望在数据结构中存储一个单词列表,以有效支持“字谜”问题。也就是说,对于一个由n个字母组成的“架子”,该单词列表中可以从该架子中制作出所有n个或更少字母的单词。单词列表将约有400K个单词,因此未压缩时可能为1到10兆字节。

trie(字典树)是解决这个问题的经典数据结构,因为它结合了内存效率和搜索效率。对于约有400K个适当长度的单词的单词列表,您应该能够将trie保留在内存中。(与使用B-Tree的解决方案相比,后者需要将大部分树保存在磁盘上,因为它太大而无法一次性放入内存中。)

Trie基本上只是一个26叉树(假设您使用罗马字母表),每个节点都有一个字母和每个节点上额外的一个位表示它是否是单词的结尾。

现在,让我们来设计这个数据结构:

class TrieNode
{
    char Letter;
    bool IsEndOfWord;
    List<TrieNode> children; 
}

当然,这只是一个草图;你可能想要为它们创建适当的属性访问器和构造函数等等。另外,也许平面列表不是最好的数据结构;也许某种类型的字典更好。我的建议是先让它工作起来,然后测量其性能,如果性能不可接受,再尝试进行改进。

你可以从一个空的trie开始:

TrieNode root = new TrieNode('^', false, new List<TrieNode>());

也就是说,这是代表单词开头的“根”trie节点。

如何添加“AA”这个单词,它是Scrabble词典中的第一个单词?首先,为第一个字母创建一个节点:

root.Children.Add('A', false, new List<TrieNode>());

好的,我们现在的 trie 树是:

^
|
A

现在添加一个节点表示第二个字母:

root.Children[0].Children.Add(new trieNode('A', true, new List<TrieNode>()));

我们现在的trie树是

^
|
A
|
A$   -- we notate the end of word flag with $

很好。现在假设我们想添加AB。我们已经有了一个节点代表"A",所以将"B$"节点添加到它上面:

root.Children[0].Children.Add(new trieNode('B', true, new List<TrieNode>());

现在我们有了

    ^
    |
    A
   / \
  A$   B$

继续保持这样的进展。当然,你将不再写"root.Children[0]...",而是编写一个循环来搜索trie,查看是否存在所需的节点,如果不存在,则创建它。

要将trie存储在磁盘上--坦白地说,我会将单词列表存储为纯文本文件,并在需要时重新构建trie。这不应该花费超过30秒的时间,然后您可以在内存中重复使用trie。如果您确实想以更像trie的格式存储trie,那么想出一种序列化格式应该不难。

为了搜索匹配rack的trie,思路是探索trie的每个部分,但修剪掉无法与rack匹配的区域。如果rack上没有任何"A",则无需深入任何"A"节点。我在您之前的问题中勾勒出了搜索算法。

我有一个功能性的持久trie实现,我一直想博客上发布一下,但一直没有实现。如果我最终发布了,我会更新这个问题。


1
我不清楚问题是什么,但这是一个Trie的清晰解释。此外,如果您可以通过移动相机OCR扫描Scrabble棋盘... - Jodrell
@Jodrell:哈夫曼树是为了不同的目的而设计的,但我可以理解为什么你在这里想起了哈夫曼树。 - jason
1
我在等待这篇博客文章 ;) - Random Dev
嘿,没问题 - 慢慢来 - 我只是想鼓励你一下 ;) (现在我重新阅读它,我可以看出这可能被解释为“天哪,我的文章在哪里” - 对一个非英语的人要有怜悯心) - Random Dev
1
@Brian,那通常被称为 Patricia Trie 或 Radix Trie。http://en.wikipedia.org/wiki/Radix_tree - ShuggyCoUk
显示剩余7条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接