【问题标题】:Do all Hash-based datastructures in java use the 'bucket' concept?java中所有基于哈希的数据结构都使用“桶”概念吗?
【发布时间】:2010-12-19 23:40:12
【问题描述】:

我知道的哈希结构 - HashTable、HashSet 和 HashMap。

它们都使用桶结构吗?即当两个哈希码相似 完全相同一个元素不会覆盖另一个元素,而是将它们放在同一个桶中与该哈希码相关联?

【问题讨论】:

  • 我想你的问题可能不清楚。当您说“哈希码相似”时,您是否试图询问哈希冲突?一个元素覆盖另一个元素是什么意思?
  • 当两个元素从 Object.hashcode() 返回相同的 int哈希冲突)

标签: java hashtable hashmap hashcode data-structures


【解决方案1】:

HashSet 除外。 Set 根据定义是唯一的元素。

这是一个错误。请参阅下面的 cmets。

【讨论】:

  • -1: 不同的元素可能有相同的 Hash - 它们都会被添加
  • 这并不排除哈希码冲突。对于不相等的对象,集合仍然必须处理它们。无论如何,HashSet 只是实现中 HashMap 的包装器。
  • 问题不在于重复元素。这是关于具有相同散列元素的元素。一个哈希集当然可以包含多个具有相同哈希码的对象。
  • 我误读了关于相等元素而不是具有相同哈希码的元素的问题。我很抱歉。我现在就删帖。
【解决方案2】:

Maps 和 Sets 是决定 HashSet 或 HashMap 行为的接口。 HashSet 是一个集合,因此它的行为类似于集合(即不允许重复)。 HashMap 的行为类似于 Map - 它不会用 similar 哈希码覆盖键,但如果再次使用相同的确切键,它会覆盖键。无论内部支持 Map 的数据结构是什么,这都是相同的。有关更多信息,请参阅 javadoc 了解 Sets 和 HashMaps。

您的意思是要问一些关于其中一种结构的具体实现的问题吗?

【讨论】:

  • 所以如果我有两个不相同的对象(equals() 失败)但从 hashcode() 返回相同的 int,当两个对象放在同一个 HashSet 中时,一个对象会覆盖另一个对象吗?
  • 是的,如 Set 的 javadoc 中所述,(java.sun.com/javase/7/docs/api/java/util/Set.html#add(E)) 相同性的最终定义是 equals()。引用:“更正式地说,如果集合不包含元素 e2,则将指定的元素 e 添加到此集合中 (e==null ? e2==null : e.equals(e2))。”
【解决方案3】:

在 Sun 当前的 Java 库实现中,IdentityHashMapThreadLocal 中的内部实现使用探测结构。

在 Java 中探测哈希表的一般问题是 hashCodeequals 可能相对昂贵。因此,您要缓存哈希值。你不能有一个混合引用和原语的数组,所以你需要做一些相对复杂的事情。另一方面,如果您使用== 来检查匹配项,那么您可以检查许多引用而不会出现性能问题。

IIRC,Azul 有一个快速并发二次探测哈希图。

【讨论】:

  • 可能是一个很好的答案,但有点超出我的想象 - 探测结构是什么意思?你的意思是在比较哈希时?
  • 证明是亚当·罗森菲尔德回答中开放寻址的同义词。
  • @TomHawtin-tackline 我在这里有一个基本的question on probing。你能试着回答一下吗?
【解决方案4】:

否 -- open addressing 是表示哈希表的另一种方法,其中对象直接存储在表中,而不是驻留在链表中。给定索引只能存储一个对象,因此解决冲突更加复杂。

当添加另一个对象已经存在于同一索引中的对象时,将使用探测序列来确定存储新对象的新索引。移除对象也比较复杂,因为如果你移除一个对象,你需要留下一个标记,上面写着“这里曾经有一个对象”;有关详细信息,请参阅维基百科。

当存储的对象很小并且很少被删除时,最好使用开放寻址。开放寻址提高了缓存性能,因为您无需通过额外的间接级别来遍历链表。

您提到的类 -- HashTableHashSetHashMap 不使用开放寻址,但您可以轻松创建实现开放寻址并提供与这些类相同的 API 的新类。

【讨论】:

    【解决方案5】:

    链表在每个桶中用于处理哈希冲突。请注意,java HashSet 实际上是由下面的HashMap 实现的(所有键都映射到所有HashSets 中的相同单例值),因此使用相同的桶结构。 p>

    如果添加了一个元素,则在将其添加到末尾之前,将针对链接列表中的所有项目(通过.equals)检查其是否相等。因此,哈希冲突特别糟糕,因为随着链表变大,这可能是一项昂贵的检查。

    【讨论】:

    • 一个(单)链表,但不是 LinkedList!
    • HashTable 的实现方式是否类似,还是独立于您上面描述的两者?
    【解决方案6】:

    API 定义了行为,如何管理哈希冲突的内部结构不会影响 API 的保证……糟糕的哈希值计算对性能的影响是另一回事。让我们将所有内容哈希为 42,然后看看它的行为。

    【讨论】:

      【解决方案7】:

      我相信 Java 散列结构在执行散列时都使用一种链接形式来处理 colisions - 将具有相同散列的项目放入列表中。

      我不认为 Java 将开放寻址用于其基于散列的数据结构(开放寻址会根据重试序列重新计算散列,直到在表中找到一个开放缝)

      【讨论】:

      • 对于那些说“我相信”不够好的人……请放心。上述说法属实。我与 docjar.com 确认。也就是说,HashMap 使用链接(自定义构建的链表,而不是 java.util.LinkedList)。它不使用开放寻址。
      猜你喜欢
      • 2012-02-19
      • 1970-01-01
      • 2011-03-02
      • 1970-01-01
      • 2021-09-24
      • 2018-05-30
      • 1970-01-01
      • 2020-01-09
      • 1970-01-01
      相关资源
      最近更新 更多