如何实现字典(Trie vs HashTable和重要问题)?

我遇到了几个问题和文章,说java中的字典实现最好使用尝试来完成。但就我所看到的,他们中的大多数都没有解决重要问题。所以,接下来是一个现实世界的任务:

让我们假设我需要使用java实现一个字典(让我们说像Lingvo一样的东西,但更简单)。对于我的特定任务,需要存储单词定义并执行快速字典查找。

请解决以下问题:

  • 那么我应该使用什么数据结构(Trie或HashTable)?
  • 如果我需要字典不区分大小写,它应该如何组织(搜索,数据结构)?
  • 如果我希望它(搜索,字典)区分大小写怎么办?

P.S.:代码示例非常值得赞赏。:)

提前感谢您的回答。

更新:如果我们谈论Java中的标准DS实现,那么HashTable真的是这个特定任务的最佳实现吗?为什么不是HashMap,TreeMap或LinkedHashMap?


答案 1

我想在你的问题中只解决一点:

trie 不是通用的字典数据结构。原因是 trie 是(子)字符串搜索的专用搜索树。通常,您会对常规搜索树更感兴趣,例如二叉搜索树B树

所有这些实现都依赖于字典元素的排序,并且它们都具有常见操作的对数平均情况和最坏情况运行时。

相比之下,哈希表不需要元素的相对排序。相反,它要求元素是可哈希的并且相等可比。常见哈希表特征的最坏情况特征比树差得多,即元素数量的线性。

但是,稍微小心一下,哈希表操作的平均情况可以保持恒定(即独立于容器大小)。更重要的是,可以证明,较慢的操作是非常罕见的。

在实践中,这意味着除了非常专业的用例之外,哈希表击败了基于树的字典。

这样做的缺点是哈希表对其元素施加了看似任意的顺序。如果您有兴趣按排序顺序从字典中获取项目,则哈希表不适合您。

(字典还有其他有趣的实现,例如跳过列表,可与搜索树和概率实现(如Bloom过滤器)相媲美。

只有在处理字符串值的字典时,才能使用基于 trie 的实现,在这种情况下,它实际上通常是一个不错的选择,特别是如果字典中的许多字符串共享公共前缀并且相当短。


答案 2

编辑停止投票:我误读了这个问题。OP不是在字典之后验证单词拼写/建议/键入-提前查找/自动完成/任何东西(我认为这是他所追求的)。OP是在键/值映射之后,其中每个单词都有一个定义。

在研究过字典之后,我可以告诉你,你采取了错误的方法。

这并不像在哈希表或trie之间进行选择那么简单。

你提到Lingvo:它不仅仅是一张桌子。

您是否希望提供紧密匹配的建议?然后,您可能需要对用户输入的内容生成排列,并针对每个排列查看它是否存在于dico中:如果存在,则需要计算其“Levenhstein编辑距离”,并首先建议具有最短LED的单词。

您是否希望自动完成/建议最有可能的匹配(就像Google所做的那样)?然后,您需要一个非常高级的数据结构,例如BK树(如果我理解正确,基本上是LED树)。

你的字典里有多少个单词?您将无法使用由字符串和其他重量级Java对象/数据结构组成的400 000个单词组成的字典而不会对性能造成严重打击(再次:字典不仅仅是一个哈希表,字典通常涉及多个数据结构)。这不容易放入用户的计算机内存中。有一些已知的,可搜索的,存储单词的方法,其中每个单词都可以打包在每个单词少于15位(每个单词少于15位,你读得正确)。

除此之外,您可能还想根据语音学提出建议:例如使用双元音映射。

字典,就像“单词字典”一样,不仅仅是一个键/值表。这实际上是一个复杂的野兽,因为用户应该除了哪些功能,并且由于涉及的数据量。只是简单的英语+一些专业领域的术语,医学,comp-sci,等等。将为您提供数十万的数据:尝试将其放入Java HashMap中,然后...咔嚓!