无法从Sun文档中了解Hash表的Poisson部分

时间:2013-12-08 00:37:09

标签: java hashmap poisson

我试图了解如何在Java中实现HashMap。我决定尝试理解该课程的每一行(代码和评论),显然我很快就遇到了阻力。以下代码片段来自HashMap类,并讨论泊松分布:

  
      
  • 理想情况下,在随机hashCodes下,频率为
  •   
  • 箱中的节点遵循泊松分布
  •   
  • http://en.wikipedia.org/wiki/Poisson_distribution)with
  •   
  • 默认调整大小的平均值约为0.5
  •   
  • 阈值为0.75,但由于
  • 而存在较大差异   
  • 调整粒度。忽略差异,预期
  •   
  • 列表大小k的出现是(exp(-0.5)* pow(0.5,k)/
  •   
  • 阶乘(K))。第一个值是:   *
  •   
  • 0:0.60653066
  •   
  • 1:0.30326533
  •   
  • 2:0.07581633
  •   
  • 3:0.01263606
  •   
  • 4:0.00157952
  •   
  • 5:0.00015795
  •   
  • 6:0.00001316
  •   
  • 7:0.00000094
  •   
  • 8:0.00000006
  •   
  • 更多:不到千万分之一
  •   

我是数学界的普通人,必须先了解泊松分布是什么。感谢简单的视频向我解释。

现在,即使了解了如何使用Poisson计算概率,我也无法理解上述内容。

有人可以用更简单的语言解释一下,如果可能,请举例说明吗?这将使我的任务更有趣。

提前致谢

2 个答案:

答案 0 :(得分:6)

根据要插入的元素的hashCode,将HashMap组织为“桶”数组。每个存储桶(默认情况下)是元素的链接列表。每个桶只有很少的元素(理想情况下,最多只有一个),因此找到一个特定元素只需要很少搜索链表。

举一个简单的例子,假设我们有一个容量为4的HashMap和一个0.75的加载因子(默认值),这意味着它在调整大小之前最多可以容纳3个元素。元素到桶中的理想分布看起来像这样:

bucket | elements
-------+---------
     0 | Z
     1 | X
     2 |
     3 | Y

因此可以立即找到任何元素,而无需在存储桶中进行任何搜索。另一方面,元素分布非常差,如下所示:

bucket | elements
-------+---------
     0 | 
     1 | Z -> X -> Y
     2 |
     3 |

如果所有元素都碰巧散列到同一个存储桶中,则会发生这种情况,因此搜索元素Y将需要遍历链接列表。

这可能看起来不是什么大问题,但是如果你有一个容量为10,000个元素的HashMap,并且链表上的一个存储桶中有7,500个元素,那么搜索特定元素会降低到线性搜索时间 - - 这是使用HashMap试图避免的。

一个问题是用于将元素分配到存储桶的hashCode由对象本身决定,而对象的hashCode实现并不总是非常好。如果hashCode不是很好,那么元素可以在某些桶中聚集,并且HashMap将开始表现不佳。

代码中的评论是关于每个桶中出现不同长度的链表的可能性。首先,它假设hashCodes是随机分布的 - 情况并非总是如此! - 我认为它还假设HashMap中的元素数量是桶数量的50%。根据这些假设,根据Poisson分布,60.6%的桶将是空的,30.3%将具有一个元素,7.5%将具有两个元素,1.2%将具有三个元素,等等。

换句话说,鉴于那些(理想的)假设,每个桶中的链表通常都很短。

在JDK 8中,有一种优化方法可以将链表转换为高于某个阈值大小的树,这样在最坏的情况下至少性能会降低到O(log n)而不是O(n)。问题是,应选择什么值作为阈值?这就是讨论的全部内容。当前阈值TREEIFY_THRESHOLD是8.再次,在这些理想假设下,具有长度为8的链表的桶将仅出现0.000006%的时间。因此,如果我们得到一个很长的链表,那么显然不理想!!例如,它可能意味着存储的对象具有特别糟糕的hashCode,因此HashMap必须从链表切换到树,以避免过度的性能下降。

带有相关评论的源文件的链接在这里:

http://hg.openjdk.java.net/jdk8/jdk8/jdk/file/jdk8-b119/src/share/classes/java/util/HashMap.java

答案 1 :(得分:2)

接受的答案很棒,但我只是想填写为什么特别适合使用泊松分布,因为在阅读那段代码时我有完全相同的问题。

如果我们将固定数量的项k插入到固定数量的存储区n中,那么固定存储区中的项目数应遵循Binomial Distribution k试验和成功的可能性1 / n。这很容易看到;如果哈希值是随机的,则每个项目都会以概率1 / n放入我们的存储桶中,并且有k项。

k很大且二项分布的均值很小时,一个好的近似值是Poisson Distribution,具有相同的均值。 在这种情况下,均值为k / n,哈希表的加载因子。取0.5的平均值是合理的,因为在调整大小之前,表允许负载因子最多为0.75,因此将使用该表 负载系数大约为0.5。