何时使用哈希映射或树图?
我知道当我需要对它们进行排序时,我可以使用TreeMap迭代元素。
但就是这样吗? 当我只想查阅地图或一些最佳的特定用途时,没有优化?
-
地图之间存在显着差异。 TreeMap是NavigableMap(并已排序)。 它有一些有趣的属性,比如根据当前键找到next / prev值/键,但是需要[自然]键的顺序,而HashMap是......基于哈希的,所以直接比较不是很合适。 如果你没有定义自然顺序(想想像java.util.URL)你就不能真正使用TreeMap。 此外,对象比较通常是淋浴而不是哈希码/等于。
-
非常感谢,很好的答案是互补的。 我更清楚何时使用它们。 感谢您的链接。
-
你可以看到[在这里输入链接描述] [1] [1]:stackoverflow.com/questions/2444359/…
TreeMap提供保证的O(log n)查找时间(和插入等),而如果哈希码适当地分散键,则HashMap提供O(1)查找时间。
除非您需要对条目进行排序,否则我会坚持使用HashMap。或者当然有ConcurrentHashMap。我不记得所有这些之间差异的细节,但HashMap是一个非常合理的"默认"选项:)
为了完整起见,我应该指出,大约一个月前有关于各种地图内部的Stack Overflow的讨论。请参阅此问题中的评论,如果我很高兴我这样做,我会将其复制到此答案中。
-
我想这更适用于"TreeSet vs HashSet",但假设我经常设置交叉点。在这种情况下,对元素进行排序通常是净胜利,即使您没有明确使用它们的排序。
-
@phooji:这是有道理的,是的,假设交叉码是经过适当优化的。如你所说,它不太可能与地图相关。
-
@Jon,我想我是那个人(指出Java中HashMap的弱点)
-
@bestsss:很可能。你还记得讨论的地方吗?如果我们能找到它,你介意我直接将它发布到这个答案吗?
-
@bestsss:找到它:stackoverflow.com/questions/4815869/… - 同样的问题仍然适用:)
-
@Jon,我把LinkedHashMap作为默认Map。它具有更好且可预测的迭代(如LinkedList),它不会改变w / java版本或hashmap impl。
Hashtables(通常)执行在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的默认实现不允许重复)
还有一些特殊情况需要考虑,例如,如果特定数据结构中的元素数量不受限制地增加或接近数据结构的基础部分的限制,该怎么办?那些执行一些重新平衡或清理操作的摊销操作呢?
例如,在散列表中,当表中的元素数量变得足够大时,可以发生任意数量的冲突。另一方面,树插入(或删除)后通常需要重新平衡过程。
所以,如果你有类似缓存的东西(例如有界的元素数量,或者已知大小),那么散列表可能是你最好的选择;但是,如果你有更像字典的东西(例如,填充一次,并且多次查找),那么我会使用一棵树。
然而,这只是在一般情况下(没有给出任何信息)。您必须了解在决定使用哪种数据结构时如何做出正确选择的过程。
当我需要一个多映射(范围查找)或分类扁平化集合时,它不能是一个哈希表。
-
我不同意你使用树作为一个结构的例子,该结构将被填充一次并被多次引用。在这种情况下,您可以创建一个适当大小的Hashtable,它具有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
两者之间的最大差异是实现中使用的底层结构。
HashMaps使用数组和散列函数来存储元素。当您尝试插入或删除数组中的项时,哈希函数会将键转换为数组中应存储对象的索引(忽略冲突)。虽然哈希映射通常非常快,因为它们不需要迭代大量数据,但它们在填充时会变慢,因为它们需要将所有键/值复制到新数组中。
TreeMaps将数据存储在已排序的树结构中。虽然这意味着他们永远不必分配更多空间并复制到它,但操作需要迭代已经存储的部分数据。有时会改变大量的结构。
当您不需要排序时,两个Hashmaps中通常会有更好的性能。
不要忘记还有LinkedHashMap,它几乎与HashMap一样快,用于添加/包含/删除操作,但也保持插入顺序。
-
contains完全一样快,LinkedHashMap的迭代速度更快(相当多)。
-
嗯,也许我应该经常使用它!
-
get()几乎同样快,除非它创建了w / accessOrder=true然后它只是几(6)个赋值和一个间接(几乎没有)。 LinkedHashMap是我在java.util中最喜欢的结构。
平均而言,将新元素插入HashMap比将元素插入TreeMap要快得多。除非您需要对元素进行排序,否则我将使用HashMap。