我正准备参加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究竟是如何为自己添加项目的呢?
答案 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
按顺序遍历存储桶。在同一个存储桶中,使用了插入顺序。
因此订单是:
这符合选择&#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)
。