【问题标题】:How does the search algorithm work with objects in a java collection such as HashSet?搜索算法如何处理 Java 集合(如 HashSet)中的对象?
【发布时间】:2012-01-02 09:58:05
【问题描述】:

问题实际上是关于在集合中动态变化的对象。 “包含”方法是每次都单独比较每个对象还是做一些聪明的事情?

如果您在一个集合中有 10000 个条目,我预计它会更聪明地工作,但不确定。或者如果没有,有没有办法通过添加一个钩子来优化它,告诉集合对象更新已更改对象的哈希码??

补充问题:

感谢下面的回答...我还可以问一下 ArrayList 的情况吗?我在文档中找不到任何说明不要将可变对象放入 ArrayList 的内容。这是否意味着搜索算法只是简单地与每个对象的哈希码进行比较??

【问题讨论】:

  • HashSet 中的对象不能改变。

标签: java hashtable hashset


【解决方案1】:

他们散列对象并通过其散列码查找它。如果它在那里,它将比较对象本身。这是因为具有相同散列的两个或多个对象可能不是同一个对象。

由于 Java 的哈希集合使用桶(链式),它们必须查看桶中的所有对象。这些对象保存在一个链表中(不是java.util.LinkedList,而是一个自定义列表)

这通常是非常有效的,HashSet.contains() 方法是amortized O(1)(恒定时间)。


Java's docs对你问题的第二部分有答案:

注意:如果将可变对象用作集合元素,则必须非常小心。 如果对象的值以影响相等比较的方式更改,而对象是集合中的一个元素,则不指定集合的​​行为。这种禁止的一个特殊情况是不允许集合包含自己作为元素。

【讨论】:

  • 对象(内部变量)会发生什么变化。或者集合知道对象的更改哈希。我认为他们使用某种排序的哈希,因此可以更快地找到对象....否则它必须通过所有对象检查哈希对吗??
  • 来自 JavaDoc:“注意:如果将可变对象用作映射键,则必须非常小心。如果对象的值以影响的方式更改,则未指定映射的行为等于比较,而对象是映射中的键。此禁令的一个特殊情况是,不允许映射将自身作为键包含。虽然允许映射将自身作为值包含,但要格外小心建议:equals 和 hashCode 方法在这样的地图上不再定义良好。download.oracle.com/javase/7/docs/api/java/util/Map.html
  • 感谢您的澄清。我接受 Ruakh 的回答,尽管他首先指出了这一点.. :) 1+ 的答案。
  • 请注意,“查看所有对象”并不意味着“对所有对象调用 equals”——它会记住哈希码,因此只需对桶,以及对真正具有匹配哈希码的元素进行可能昂贵的相等检查。
  • @NullUserExceptionఠ_ఠ:不——否则你可能会有一张巨大的桌子。例如,看看HashMap 的实现 - 你可以得到几个具有 congruent 哈希码(mod 表长度)的对象。快速迭代那些只检查具有完全相同哈希码的那些。如果您对此一无所知,则不清楚您所说的“由于 Java 的哈希集合使用存储桶 [...]”是什么意思 - any 基于哈希的实现必须允许多个元素相同的哈希码。
【解决方案2】:

HashSet 在将元素添加到集合时计算它的 hash code。它以一种可以非常高效地找到具有相同哈希码的所有元素的方式存储它。

然后当您调用contains() 时,它只需要计算您正在查找的值的哈希码,并找到集合中具有相同哈希码的所有元素。可能有多个元素,因为哈希码不是唯一的,但具有匹配哈希码的元素可能比集合本身中的元素少得多。然后使用equals 检查每个匹配元素,直到找到匹配项或我们的候选者用完为止。

编辑:要回答第二部分,不知何故我在第一次阅读时错过了,您将无法再次找到该元素。您不得以任何影响相等的方式更改用作哈希表中的键的元素或哈希集中的元素,否则您基本上会破坏事情。

【讨论】:

  • 添加到集合后对象内容发生变化会发生什么?然后对象的哈希码发生了变化。集合如何知道新的更新值?
  • @SidMalani:没有,你也找不到。记录在案在这种情况下工作。
【解决方案3】:

简单的答案是——不,没有什么聪明的事情发生。如果您希望对象的状态以影响其hashCode()equals(...) 行为的方式发生变化,那么您不得将其存储在HashSet 或任何其他Set 中。引用http://download.oracle.com/javase/6/docs/api/java/util/Set.html:

注意:如果将可变对象用作集合元素,则必须非常小心。如果对象的值以影响equals 比较的方式更改,而对象是集合中的一个元素,则不指定集合的​​行为。此禁令的一个特殊情况是不允许集合包含自身作为元素。

【讨论】:

  • 感谢您回答我的问题 1+。干杯
【解决方案4】:

HashSet 在后台使用HashMap。因此,contains 操作使用对象中的hashCode() 方法来检查它是否存在于HashMap 实现的哈希表中。

【讨论】:

    猜你喜欢
    • 2017-11-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-21
    • 2016-04-15
    • 1970-01-01
    相关资源
    最近更新 更多