树图还是哈希图? [复制]

Posted

技术标签:

【中文标题】树图还是哈希图? [复制]【英文标题】:TreeMap or HashMap? [duplicate] 【发布时间】:2011-07-16 19:22:14 【问题描述】:

何时使用哈希图或树形图?

我知道当我需要对元素进行排序时,我可以使用 TreeMap 来迭代它们。 但仅此而已吗?只想看图的时候没有优化,或者一些优化的具体用途?

【问题讨论】:

地图之间存在显着差异。 TreeMapNavigableMap (并已排序)。它有一些有趣的属性,比如根据当前键查找下一个/上一个值/键,但是需要键的 [自然] 顺序,而 HashMap 是......很好地基于散列,所以直接比较不是很合适。如果你没有定义自然顺序(想想 java.util.URL)你就不能真正使用 TreeMap。此外,对象比较通常比 hashcode/equals 更小。 非常感谢,很好的答案是互补的。我更清楚何时使用它们。也感谢您的链接。 可以看到[在此处输入链接描述][1][1]:***.com/questions/2444359/… 【参考方案1】:

平均而言,将新元素插入 HashMap 比将元素插入 TreeMap 快很多。除非您需要对元素进行排序,否则我会使用 HashMap。

【讨论】:

【参考方案2】:

TreeMap 提供有保证的 O(log n) 查找时间(和插入等),而 HashMap 提供 O(1) 查找时间,如果哈希码适当地分散键。

除非您需要对条目进行排序,否则我会坚持使用HashMap。当然还有ConcurrentHashMap。我不记得所有这些差异的细节,但HashMap 是一个完全合理的“默认”选项:)

为了完整起见,我应该指出,大约一个月前在 Stack Overflow 上讨论了各种地图的内部结构。请参阅comments in this question,如果 bestsss 愿意我这样做,我会将其复制到此答案中。

【讨论】:

我想这更适用于“TreeSet vs HashSet”,但假设我经常设置交叉点。在这种情况下,对元素进行排序通常是一种净赢,即使您没有明确使用它们的排序性。 @phooji:这是有道理的,是的,假设交集代码经过适当优化。正如您所说,它不太可能与地图相关。 @Jon,我猜我就是那个人(指出java中HashMap的弱点) @bestsss:很可能。你还记得讨论在哪里吗?如果我们能找到它,您介意我直接将其发布到这个答案中吗? @bestsss:找到它:***.com/questions/4815869/… - 同样的问题仍然适用 :)【参考方案3】:

别忘了还有LinkedHashMap,它几乎与HashMap 一样快,用于添加/包含/删除操作,但也保持插入顺序。

【讨论】:

contains 完全一样快,LinkedHashMap 的迭代更快(相当快)。 嗯,是的,也许我应该更频繁地使用它! get() 实际上和accessOrder=true 一样快,除非它创建了 w/accessOrder=true,然后它只是几 (6) 个分配和一个间接(几乎没有)。 LinkedHashMap 是我在 java.util 中最喜欢的结构。【参考方案4】:

哈希表(通常)在O(n)<=T(n)<=O(1) 的复杂度范围内执行搜索操作(查找),平均情况复杂度为O(1 + n/k);但是,二叉搜索树(BST)执行的搜索操作(查找)的复杂度为O(n)<=T(n)<=O(log_2(n)),平均情况复杂度为O(log_2(n))。每个(和每个)数据结构的实现应该(由您)知道,以了解操作的优点、缺点、时间复杂性和代码复杂性。

例如,哈希表中的条目数通常具有一些固定数量的条目(其中某些部分可能根本没有被填充)与冲突列表。另一方面,树通常每个节点有两个指针(引用),但如果实现允许每个节点有两个以上的子节点,这可能会更多,这允许树随着节点的添加而增长,但可能不允许重复。 (Java TreeMap 的默认实现不允许重复)

还有一些特殊情况需要考虑,例如,如果特定数据结构中的元素数量无限制地增加或接近数据结构底层部分的限制,该怎么办?执行一些重新平衡或清理操作的摊销操作呢?

例如,在哈希表中,当表中的元素数量变得足够多时,可能会发生任意数量的冲突。另一方面,树通常需要在插入(或删除)之后进行重新平衡过程。

因此,如果您有类似缓存的东西(例如,有界元素的数量或大小已知),那么哈希表可能是您最好的选择;但是,如果您有更像字典的东西(例如填充一次并多次查找),那么我会使用一棵树。

不过,这只是一般情况(未提供任何信息)。您必须了解发生的过程,他们如何在决定使用哪种数据结构时做出正确的选择。

当我需要多映射(范围查找)或集合的排序展平时,它不能是哈希表。

【讨论】:

我不同意您将树用于结构的示例,该结构将被填充一次并被多次引用。在这种情况下,您可以创建一个适当大小的哈希表,它具有 O(1) 的查找性能,而基于树的结构的查找性能为 O(log n)。此外,您永远不会使用 Hashtable 的线性运算。 @ChrisKerekes,您可以创建完美匹配的哈希表,并且不会发生冲突,使其成为 O(m) 并获得承诺的 O(1)。但是您需要为您的数据生成良好的哈希函数(并非总是可以花费一些空的额外条目来更改哈希函数行为)。否则,我认为通用哈希表更适合快速和平缓存。 O(n)<=T(n)<=O(1) 正确吗? @f.ardelian,我也不明白。 @alvonellos 承诺这些是技术细节。可能它应该是 O(1) ≤ T(n) ≤ O(n) 用于哈希表,T(n) = O(log n) 用于平衡树(我记得常量可以从 O 表示法中去除)。 这里是基于集合大小的一些数字的性能测试:artima.com/weblogs/viewpost.jsp?thread=122295【参考方案5】:

两者最大的区别在于实现中使用的底层结构。

HashMaps 使用数组和散列函数来存储元素。当您尝试在数组中插入或删除项目时,散列函数将键转换为数组上的索引,该对象是/应该存储的(忽略冲突)。虽然哈希图通常非常快,因为它们不需要迭代大量数据,但在填充时它们会变慢,因为它们需要将所有键/值复制到新数组中。

TreeMap 将数据存储在排序的树结构中。虽然这意味着他们永远不必分配更多空间并复制到它,但操作需要对已存储的部分数据进行迭代。有时会改变大量的结构。

在不需要排序的情况下,这两个 Hashmap 通常会有更好的性能。

【讨论】:

以上是关于树图还是哈希图? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

哈希图共识算法

如何在 javascript 中检查此布尔哈希图是不是为空? [复制]

如何“忽略”哈希图的模板参数?

哈希图和向量很慢

可变哈希图键是一种危险的做法吗?

React Native:键值数组还是哈希图?