Java 使用嵌套哈希映射实现TRIE?
使用嵌套的哈希映射创建TRIE有什么好处 例如,让我们有一个嵌套的哈希映射,其中每个映射只有一个字符的键。因此,对于单词“Dog”,我们会有类似于Java 使用嵌套哈希映射实现TRIE?,java,algorithm,data-structures,hashmap,trie,Java,Algorithm,Data Structures,Hashmap,Trie,使用嵌套的哈希映射创建TRIE有什么好处 例如,让我们有一个嵌套的哈希映射,其中每个映射只有一个字符的键。因此,对于单词“Dog”,我们会有类似于myHashMap['d']['o']['g']['*']=True的东西。 末尾的“*”表示条目的结尾 在书中,我从未见过这种方法,而是“经典”节点类。为什么? 如果每个节点只有256个条目,为什么你会考虑一个哈希图?如果将hashmap变小,则会增加较低节点上发生冲突的风险,并且这些良好的属性将消失。。。如果你让它动态化,你会得到所有的管理开销 当
myHashMap['d']['o']['g']['*']=True的东西。
末尾的“*”表示条目的结尾
在书中,我从未见过这种方法,而是“经典”节点类。为什么? 如果每个节点只有256个条目,为什么你会考虑一个哈希图?如果将hashmap变小,则会增加较低节点上发生冲突的风险,并且这些良好的属性将消失。。。如果你让它动态化,你会得到所有的管理开销
当你声明你的嵌套hashmap时,你会把它做多深
如果它不是一个固定的深度,那么您只需要使用hashmap作为节点来复制一个“节点”方法
hashmap->hashmap->hashmap将占用更多的空间,并且比仅仅使用字符串的散列要慢
Hashmaps没有排序-因此现在您有了一个未排序的映射,而这实际上不是trie
这是一个很好的问题,也是我目前正在思考的问题
Glenn的回答没有考虑到Trie(或前缀树,换个名字)的前缀存储性质。如果您只需要一个字典,那么哈希表是一个更好的选择,但是如果您想做一些自动完成样式的事情,那么Trie是理想的选择。对于Trie,我也不了解它需要排序
我想您提到的“经典”方法是使用字符索引数组O(1)查找来引用任何节点的子节点。这对于小字母表来说是快速且节省空间的,但正如您所观察到的,对于非常大的字符集(Unicode),空间很快就会变得不可用
您提到的另一种方法是在每个节点上都有一个HashMap,将每个字符映射到子节点。保留索引数组的恒定查找时间(假设是真正的哈希实现),并且希望每个节点不使用数千字节来存储空字符槽
在我看来这是一场胜利,所以我也想知道为什么我没有经常提到它
一个混合方法,我认为,如果你知道前面的整个字母表,把char ->数组索引(连续索引到你的子数组)中的哈希映射保持在两个世界的最好位置。只需预先扫描字典,告诉Trie您将在构建时使用哪些unicode字符。
Map<Character, TrieMap<K, V>> children = new TreeMap<>();
因此,我通过确保无子节点不会持有浪费的空Map
(尽管我可以很容易地使用Collections.emptyMap()
)来进一步减少内存占用。什么是“经典节点类”?例如,wikipedia在没有指定节点的内部表示的情况下定义了尝试,并实际讨论了几种这样的表示。
/**
* 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<>();
}
}