我有一个包含100万个英文单词的txt文件,其频率格式为:
好的345667我需要使用Java中的HashMap或Trie数据结构来存储它。稍后我需要从列表中查找单词而不需要其他操作。我的理解是,HashMap的查找速度比Trie慢,但是Trie将占用更多的内存,而Trie的实现也需要付出努力,而HashMap已经可以使用了。对于生产代码,您对哪种数据结构最适合这种情况有什么建议或建议吗?提前谢谢。
此外,HashMap允许查找“常量时间”。它真的比英语单词的Trie慢吗?
答案 0 :(得分:5)
我的理解是,HashMap的查找速度比Trie慢,但是Trie会占用更多的内存
这是不正确的。假设一个好的散列函数,HashMap中的查找将需要对主存储器的少量常量随机访问,而不管表的大小或其密钥的长度。相反,trie需要访问密钥中每个字母的主存储器。因此,trie将导致更多的缓存未命中 - 并且在缓存未命中将主导现代硬件上的整体查找成本。
如果密钥很长并且共享许多公共前缀,则trie可以节省内存。
trie还支持前缀查询。
在您的情况下,密钥很短,并且您不需要前缀查询,因此您不会从trie中受益。
答案 1 :(得分:2)
给定一个好的散列函数(String
类肯定有),Hashmap的查找时间比Trie快。
来自维基百科,您会看到:
与不完美的哈希表相比,查找特里结构中的数据在最坏的情况下更快,O(m)时间(其中m是搜索字符串的长度)。不完美的哈希表可能存在关键冲突。密钥冲突是将不同密钥的哈希函数映射到哈希表中的相同位置。不完美哈希表中的最坏情况查找速度是O(N)时间,但更典型的是O(1),花费O(m)时间来评估哈希值。
因此,具有许多冲突的Hashmap比trie慢。但是,只有在密钥散列函数较差时才会发生这种情况。如果您使用String
个对象作为密钥,则不会出现此问题。
特里会拯救你的记忆。具体取决于数据的组成。如果数据类似,您将节省更多内存。如果数据变化,节省的费用就会减少。这是因为前缀是为具有公共前缀的字符串共享的。
因此,如果内存足够,并且您具有良好的哈希函数,请使用Hashmap。
否则,请使用Trie
。
答案 2 :(得分:2)
我猜这里的操作词是“百万”。因为许多条目散列开始遭受性能问题,而特里维持它的log(N)特性,即使机器开始大量分页。而且trie更适合基于磁盘的表(带缓存)。
但实施高效(可靠)的trie相当困难。不适合胆小的人。
答案 3 :(得分:2)
实现高效的trie绝不是微不足道的,可能最终会违背你对性能和内存使用的期望。试想一下:在每个节点中,你需要一个跳转表,它可能会将每个字符分支到一个子节点。你的潜在字符集是什么:所有Unicode,欧洲,ascii,小写和大写,只有小写。你的答案越往左,跳转表就越大。但即使只使用小写的a-z,每个节点最多需要26个条目的跳转表。速度需要在每个节点中保留26 * 4个字节。空间效率相当推动你以某种方式稀疏地存储表。在trie中更高,可能需要所有插槽,稀疏阵列将浪费空间和时间。靠近树叶,越来越少的插槽需要指向子节点并保持空白,因此一个完整而快速的表将浪费空间。
Java的HashMap有相当多的历史,可能是可用的哈希映射的最佳测试,评论,批评和改进的实现之一。根据您的要求,我会明确地从它开始,可能会对loadFactor进行一些实验,并且只有当您因HashMap而遇到严重问题时,我才会投入时间。