HashSet.contains性能

时间:2014-08-11 16:18:02

标签: java collections

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

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

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

2 个答案:

答案 0 :(得分:59)

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

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

contains方法调用({间接)getEntry HashMap 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; } 中存储两个对象。该方法迭代具有相同散列值的所有键,并在每个键上执行{{1}}以找到匹配的键。

{{1}}

答案 1 :(得分:7)

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

自平衡树保证所有操作的O(log n),因此,在哈希映射(和哈希集)中进行插入和查找的总成本为O(1)+ O(log n)= O(log n)。在Java 8中引入了使用自平衡树进行冲突处理,这是对链链接(直到Java 7为止使用)的改进,链链接使用链表,并且在查找和插入时最坏的情况是O(n) (因为它需要遍历列表)。注意,链接可以有固定的插入时间(而不是查找),因为可以将元素添加到O(1)的链表中,但是在以下情况下,链表将设置set属性(不重复)哈希图,因此在插入的情况下也需要遍历链表,以确保该元素在列表/存储桶中不存在,并且在插入和查找时都以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