【问题标题】:Implementing a TRIE with a nested hash map?使用嵌套哈希映射实现 TRIE?
【发布时间】:2013-11-22 17:12:22
【问题描述】:

使用嵌套哈希映射创建 TRIE 有什么好处?

例如,让我们有一个嵌套的哈希映射,其中每个映射只有一个字符的键。所以我们会有类似myHashMap['d']['o']['g']['*'] = True 的东西来表示“狗”这个词。 末尾的“*”表示条目的结尾。

在书中,我从未见过这种方法,而是“经典”的 Node 类。为什么?

【问题讨论】:

  • 什么是“经典节点类”?例如,维基百科定义了尝试但没有指定节点的内部表示,并且实际上讨论了几种这样的表示。

标签: java algorithm data-structures hashmap trie


【解决方案1】:

我用

Map<Character, TrieMap<K, V>> children = new TreeMap<>();

对于我的TrieMap 的实现。效果很好。

使用普通的Node 结构的好处是您可以将指向父映射的链接包装到结构中,这样您就可以更轻松地迭代映射。我没有采取那条路线并在迭代时构建Stack,因为我想确保我不会因不必要的内容而使结构膨胀。然后我在迭代时构建堆栈。

Trie 的主要好处是当键相似时它可以节省空间 - 在我看来,给结构增加不必要的重量是愚蠢的。因此我决定只使用TreeMap。另一种选择是ArrayList,但对我来说,当Trie 的数据模式很好时,它们都不像TreeMap 那样节省空间。

实际上 - 代码看起来更像:

/**
 * Map each character to a sub-trie.
 *
 * Could replace this with a 256 entry array of Tries but this will handle multi-byte character sets and I can discard
 * empty maps.
 *
 * Maintained at null until needed (for better memory footprint).
 *
 */
private Map<Character, TrieMap<K, V>> children = null;

....

/**
 * Create a new set of children.
 *
 * I've always wanted to name a method something like this.
 */
private void makeChildren() {
  if (children == null) {
    // Use a TreeMap to ensure sorted iteration.
    children = new TreeMap<>();
  }
}

所以我通过确保无子节点不会持有浪费的空Map 来进一步减少内存占用(尽管我可以很容易地使用Collections.emptyMap())。

【讨论】:

    【解决方案2】:

    这是一个很好的问题,我目前正在思考。

    格伦的回答没有考虑到 Trie(或前缀树,给它另一个名字)的前缀存储性质。如果你想要的只是一本字典,那么 Hashtable 是一个更好的选择,但如果你想做一些自动完成风格的事情,那么 Trie 是理想的选择。对于需要对其进行排序的 Trie,我也一无所知。

    我想您所指的“经典”方法是使用字符索引数组 O(1) 查找来引用任何节点的子节点的方法之一。这对于小字母来说是快速且节省空间的,但正如您所观察到的,对于非常大的字符集 (Unicode) 来说,空间很快就会变得令人望而却步。

    您提到的另一种选择是在每个节点上都有一个 HashMap ,将每个字符映射到一个子节点。您保留了索引数组的恒定查找时间(假设一个真正的哈希实现),并且您希望每个节点不使用数千个字节来存储空字符槽。

    对我来说似乎是一场全面的胜利,所以我也想知道为什么我不经常看到它被提及。

    我确实考虑过的一种混合方法是,如果您预先知道整个字母表,则保留一个 char->array 索引的哈希映射(您的子数组的连续索引),以实现两全其美。只需预先扫描您的字典,然后告诉 Trie 您将在构建时使用哪些 unicode 字符。

    【讨论】:

      【解决方案3】:

      如果每个节点只有 256 个条目,你为什么要考虑使用 hashmap?如果你让 hashmap 更小,你会增加在较低节点发生冲突的风险,并且好的属性会消失......如果你让它动态化,你会得到所有的管理开销......

      【讨论】:

        【解决方案4】:
        1. 当你声明你的嵌套哈希图时 - 你会做多深 如果它不是固定深度 - 那么您刚刚使用哈希图作为节点复制了“节点”方法
        2. hashmap->hashmap->hashmap 将占用更多空间,并且比仅使用字符串散列更慢。
        3. 哈希图未排序 - 所以现在您有一个未排序的地图,这真的不是一个尝试

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2014-03-12
          • 2021-07-22
          • 1970-01-01
          • 2017-10-04
          • 1970-01-01
          • 1970-01-01
          • 2023-01-18
          • 1970-01-01
          相关资源
          最近更新 更多