【问题标题】:How to implement a dictionary (Trie vs HashTable and important issues)?如何实现字典(Trie vs HashTable 和重要问题)?
【发布时间】:2011-01-14 12:42:43
【问题描述】:

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

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

请回答下一个问题:

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

P.S.:非常感谢代码示例。 :)

提前感谢您的回答。

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

【问题讨论】:

    标签: java algorithm data-structures dictionary lookup


    【解决方案1】:

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

    trie不是通用字典数据结构。原因是 trie 是用于(子)字符串搜索的专门搜索树。通常,您会对一般搜索树更感兴趣,例如binary search treesB-trees

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

    哈希表,相比之下,不需要元素的相对排序。相反,它要求元素是 hashableequality 可比性。普通哈希表特性的最坏情况特性比树的要差得多,即元素数量呈线性。

    不过,稍微注意一下,哈希表操作的平均情况可以恒定(即与容器大小无关)。更重要的是,可以证明较慢的操作极为罕见。

    在实践中,这意味着除了非常特殊的用例之外,哈希表完全胜过基于树的字典。

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

    (还有其他有趣的字典实现,例如 skip lists,可与搜索树和概率实现(如 Bloom filter)竞争。)

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

    【讨论】:

    • 如果我们谈论的是 java 中的标准 DS 实现,HashTable 是否真的会成为这个特定任务的最佳选择?为什么不使用 HashMap、TreeMap 或 LinkedHashMap?
    • @den-javamaniac HashTable 是线程安全的HashMap(很像VectorArrayList),因此HashMap 在您知道多个线程不会与之交互时会更好它。奇怪的是,Collections.synchronizedMap( new HashMap() )HashTable 更快,并且似乎提供了相同的安全性。 TreeMap 要求它的键是 Comparable 并使用红黑树。 LinkedHashMap 使用左/右/父引用 (IIRC) 而不是数组。这类似于ArrayListLinkedList 之间的差异。就个人而言,在 java 中,我很少使用 Linked... 集合。
    • 您的回答非常具有误导性。字典是尝试的典型应用之一。 trie 的巨大优势之一是它可以在内存方面工作,当有大量数据并且其中很多数据共享公共前缀时,哈希表会阻塞。这正是字典的含义。
    • Ups,对不起,与所有 DS 混淆(关于 HashTable 与 HashMap)。好吧,如果需要字典来存储有序单词,那么 TreeMap 似乎是最好的,不是吗?
    • @Gugussee:(已编辑!)对不起,你是对的。我以为我已经明确表示我在谈论通用字典,并且尝试仅适用于字符串搜索。但是再看一遍,根本就不清楚。我会更新我的答案。
    【解决方案2】:

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

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

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

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

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

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

    你的字典里有多少个单词?您将无法使用由 400 000 个单词组成的字典,使用字符串和其他重量级 Java 对象/数据结构而不会严重影响性能(再次重申:字典不仅仅是 one 哈希表,字典通常涉及多个数据结构)。这不会轻易放入您用户的计算机内存中。有一些已知的、可搜索的存储单词的方法,其中每个单词可以压缩到每个单词少于 15 位(每个单词少于 15 位,您没看错)。

    除此之外,您可能还想根据语音进行建议:例如使用双变音位映射。

    字典,就像在“单词字典”中一样,所以不仅仅是一个键/值表。它确实是一个复杂的野兽,由于用户应该使用哪些功能,并且涉及的数据量很大。只是简单的英语+一些专业领域术语,医学,comp-sci,等等。将为您提供数十万条数据:尝试将其放入 Java HashMap 和... Kaboom!

    【讨论】:

    • 如果说,我将有大约 200 000 个单词并且 Levenshtein 距离不包括在内,以及自动建议/竞争。您对如何组织词典有何建议?
    • @den-javamiac: 如果你真的想要像 contains(word)? 这样简单的查询类型,那么简单的 HashMap i> 会的。但是,我误读了这个问题:根据您的典型定义有多大,存储 200 000 个定义可能有问题,也可能没有问题。例如,如果每个“定义”都是维基百科条目的大小,那么您就有问题了。每个定义平均有多少个字符?
    • 假设单词定义是 50 个字符。当我需要快速字典查找和区分大小写/不区分大小写时,我仍然不明白为什么 HashTable/HashMap 会更好。你能解释一下吗?
    【解决方案3】:

    字典在 Java 中的实现,绝对是哈希集合的最佳选择。

    关于HashMapHashTable:主要是如果您的类以多线程方式使用,则必须使用HashTable,否则HashMap是最佳选择。

    HashMap vs TreeMap如果您需要在集合中插入订单,那么我们必须使用TreeMap

    HashMap vs LinkedHashMap LinkedHashMap 的实现与HashMap 的不同之处在于它维护了一个贯穿其所有条目的双向链表。这个链表定义了迭代顺序,通常是键插入映射的顺序(插入顺序)。请注意,如果将键重新插入到地图中,则插入顺序不会受到影响。 (如果m.put(k, v) 被调用,而m.containsKey(k) 将在调用之前立即返回true,则将键k 重新插入到映射m 中。)

    【讨论】:

      猜你喜欢
      • 2010-10-15
      • 2011-06-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-11-08
      • 2021-08-18
      • 2013-06-06
      • 1970-01-01
      相关资源
      最近更新 更多