繁体   English   中英

Java中HashSet.contains()的时间复杂度表现是什么?

[英]What is the time complexity performance of HashSet.contains() in Java?

我很想认为HashSet.contains(Object)方法在恒定时间内执行。 它只是获取对象的哈希码,然后在哈希表中查找。

首先,请有人确认这是否属实?

其次,如果它是真的,是否有任何冲突的风险,其中两个对象可能具有相同的哈希码,因此 HashSet 认为它同时具有两个对象,而它只有一个?

它在O(1)预期时间内运行,就像任何哈希表一样(假设哈希函数是体面的)。 它由一个HashMap支持,其中键是对象。

两个对象可能具有相同的哈希码,但HashSet不会认为它们是相同的,除非这些对象的equals方法说它们是相同的(即返回 true)。

contains方法调用(间接) getEntryHashMap ,其中关键的是Object ,而您想知道,如果它在HashSet

正如你在下面看到的,两个对象可以存储在HashMap / HashSet即使它们的键被哈希函数映射到相同的值。 该方法迭代具有相同哈希值的所有键,并对每个键执行equals以找到匹配的键。

final Entry<K,V> getEntry(Object key) {
         int hash = (key == null) ? 0 : hash(key.hashCode());
         for (Entry<K,V> e = table[indexFor(hash, table.length)];
              e != null;
              e = e.next) {
             Object k;
             if (e.hash == hash &&
                 ((k = e.key) == key || (key != null && key.equals(k))))
                 return e;
         }
         return null;
     }

contains 的最坏情况性能对于 Java 8 为 O(log n),对于 Java 7 为 O(n),但平均情况更接近 O(1)。 这是因为 hashset 由 hashmap 支持,因此具有与 hashmap 查找相同的效率(即 HashMap.get(...))。 hashmap 中的实际映射是常数时间 (O(1)),但是处理冲突的需要带来了 log n 的成本。 也就是说,散列到相同数组索引的多个元素必须存储在二级数据结构(又名存储桶)中,而正是这个存储桶决定了最坏情况下的性能。 在 Java 中,hashmap 冲突处理是使用自平衡树实现的。

自平衡树保证所有操作的 O(log n),因此,在 hashmap(和 hashset)中插入和查找的总成本为 O(1) + O(log n) = O(log n)。 在 Java 8 中引入了用于冲突处理的自平衡树的使用,作为对使用链表的链(直到 Java 7 一直使用)的改进,并且对于查找和插入具有 O(n) 的最坏情况(因为它需要遍历列表)。 请注意,链接将具有恒定的插入时间(与查找相反),因为可以在 O(1) 中将元素添加到链表中,但在hashmap,因此在插入的情况下也需要遍历链表,以确保该元素不存在于列表/存储桶中,并且我们以 O(n) 结束插入和查找。

参考:

这个类实现了 Set 接口,由一个哈希表(实际上是一个 HashMap 实例)支持。 https://docs.oracle.com/javase/8/docs/api/java/util/HashSet.html

包含大量冲突键的存储桶将在达到某个阈值后将其条目存储在平衡树中而不是链表中。 ( https://www.nagarro.com/en/blog/post/24/performance-improvement-for-hashmap-in-java-8 )

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM