String HashSet生成的输出不匹配String Hash函数

时间:2018-01-26 20:37:07

标签: java hashset

我正准备参加UIL计算机竞赛,其中一个练习题涉及到一套,这里是一字不差的:

HashSet<String> set = new HashSet<String>();
set.add("000");
set.add("212");
set.add("211");
set.add("555");
set.add("343");
System.out.println(set);

现在,我知道HashSets是未排序的数据结构,但是显示了2个未排序的选项,以及1个排序的答案选项:

A)[000,211,343,212,555]

B)[000,211,212,343,555]

c)[000,211,555,343,212]

我天真地选择了B)排序的答案,而正确答案是A,但我仍然不明白为什么。我找到了每个字符串的哈希函数生成的哈希码:

&#34; 000&#34; - 47664

&#34; 212&#34; - 49619

&#34; 211&#34; - 49618

&#34; 555&#34; - 52629

&#34; 343&#34; - 50674

据我所知,哈希集使用哈希表作为其后端。在这种情况下,根据哈希码,我不明白为什么答案是不正确的。我将代码插入到java中,并在正确的答案选择中生成结果。这里发生了什么,HashSet究竟是如何为自己添加项目的呢?

4 个答案:

答案 0 :(得分:3)

由于支持数组可能小于哈希码,因此订单不仅由hashcode()确定,而是由hashcode() % arr.length;确定。支持数组的默认大小为16,因此如果您计算所列哈希码的模数,您将获得正确的顺序。

对于具有相同哈希码的元素,首先插入的元素也是第一个要打印的元素。这是因为存储桶保存了同一存储桶中所有对象的列表(并使用equals()来确定它们是否是相同的对象,或者它们是否恰好相同桶)。

答案 1 :(得分:1)

HashSet使用HashMap作为其支持数据:

  

此类实现Set接口,由哈希表(实际上是HashMap实例)支持。

HashSet使用HashMap快速确定元素是否已存在。

HashMap的默认容量为16

  

使用默认初始容量(16)和默认加载因子(0.75)构造一个空HashMap

您已添加了5项,不足以满足负载系数乘以容量,因此无法调整大小。

您需要知道HashMap如何使用哈希码来确定要使用的存储桶。根据{{​​3}},Java确实hash & (SIZE -1)只提取最下面的 n 位,其中容量为2 n

所以,桶号如下:

&#34; 000&#34; - 47664 - &gt; 0

&#34; 212&#34; - 49619 - &gt; 3

&#34; 211&#34; - 49618 - &gt; 2

&#34; 555&#34; - 52629 - &gt; 5

&#34; 343&#34; - 50674 - &gt; 2

打印出来的集合使用了一个Iterator按顺序遍历存储桶。在同一个存储桶中,使用了插入顺序。

因此订单是:

  1. &#34; 000&#34; - 47664 - &gt; 0
  2. &#34; 211&#34; - 49618 - &gt; 2
  3. &#34; 343&#34; - 50674 - &gt; 2
  4. &#34; 212&#34; - 49619 - &gt; 3
  5. &#34; 555&#34; - 52629 - &gt; 5
  6. 这符合选择&#34; A&#34;。

答案 2 :(得分:0)

“000” - 47664

“212” - 49619

“211” - 49618

“555” - 52629

“343” - 50674

找出每个的mod除以16.然后对它进行排序。如果存在桶匹配,则最后添加的是列表中的第一个(因为它在发生冲突时“作为堆栈实现”。)

答案 3 :(得分:0)

1)问题是错误的。根据{{​​3}}的规范,

  

它不保证集合的迭代顺序;特别是,它不保证订单会随着时间的推移保持不变。

由于结果取决于实施,不应该问问题,或者答案应该是&#34;以上都不是&#34;。

2)实际实施已经改变。使用的哈希值不是key(h = key.hashCode()) ^ (h >>> 16)所熟悉的hashCode。然后,此哈希用于hash & (SIZE -1)