首页 > 解决方案 > 为什么这个 HashSet 在打印时看起来是排序的?

问题描述

Set<Integer> s = new HashSet<Integer>();
s.add(77);
s.add(0);
s.add(1);
 
System.out.println(s);
 
TreeSet<Integer> s1 = new TreeSet<Integer>();
s1.add(77);
s1.add(0);
s1.add(1);
 
System.out.println(s1);

输出:

s = [0, 1, 77]
s1= [0, 1, 77]

根据教程点页面上的定义

Set 是一组没有重复元素的通用值。TreeSet 是对元素进行排序的集合。

为什么两者的输出都是s排序s1的?我期望只s1对 ' 的输出进行排序。

标签: javacollectionshashset

解决方案


你是对的,s1因为它是排序的TreeSet,但s不是真正排序的。如果您向 中添加更多元素s,您会看到一些奇怪的事情发生。

After adding 32, 12, 13, and 14
[0, 32, 1, 12, 77, 13, 14]

所以现在你看到它有点有序,但不是真的。原因是HashSet默认容量为 16,以后会随着需要的增加而增长。因此,当您向其中添加一个元素时,想象它采用该元素的哈希码,模 16,以便它适合 16 个存储桶的内部“列表”。由于 an 的哈希码Integer是它表示的 int,我们可以假装它所做的只是 do (the element to be added) % 16

因此,当您添加 0、1 和 77 时,它可能在内部看起来像这样:

Bucket   Elements
0        0
1        1
2
3
4
5
...
13       77 (77 % 16 is 13, so it's placed here)
14
15
16

然后我们添加 32。32 % 16 为 0,但我们已经0在第一个桶中。幸运的是,为了防止这样的冲突,HashSets 使用链表而不是单个元素,因此我们只需将 32 附加到包含 0 的链表。

Bucket   Elements
0        0 -> 32
1        1  
2
3
4
5
...
13       77
14
15
16

对于 12、13 和 14,它的工作方式也相同:

Bucket   Elements
0        0 -> 32
1        1
2
3
4
5
...
12       12
13       77 -> 13
14       14
15
16

如果您按顺序遍历存储桶,打印该存储桶中的每个链表,您会得到[0, 32, 1, 12, 77, 13, 14]

看它运行


推荐阅读