【问题标题】:How is this HashSet producing sorted output?这个 HashSet 如何产生排序输出?
【发布时间】:2013-09-10 00:11:05
【问题描述】:

即使 hashset 未排序,以下代码也会生成输出 [1,2]

Set set = new HashSet();
set.add(new Integer(2));
set.add(new Integer(1));
System.out.println(set);

这是为什么呢?

【问题讨论】:

  • 使用多个测试用例。包括20个数字,看看结果是否相同。

标签: java hashset


【解决方案1】:

编辑:从 Java 8 及更高版本开始,以下内容不再适用。这证明您不应该依赖未记录的 Java 行为。


这种行为是由几个不同的原因引起的:

  • 整数自己散列
  • 在 Java 中,HashMaps 和 HashSets 由数组备份
  • 他们还使用高位修改哈希来修改低位;如果哈希值在 0..15 范围内,则不会被修改
  • 对象进入哪个桶取决于修改后哈希的低位
  • 在遍历映射或集合时,按顺序扫描内部表

因此,如果您将几个小 (

  • 整数i 具有哈希码i
  • 由于小于16,所以修改后的hash也是i
  • 它落在第 1 号桶中。 i
  • 在迭代时,桶是按顺序访问的,所以如果你存储的都是小整数,它们将按升序检索

请注意,如果桶的初始数量太小,整数可能会落在没有编号的桶中:

HashSet<Integer> set = new HashSet<>(4);
set.add(5); set.add(3); set.add(1);
for(int i : set) {
  System.out.print(i);
}

打印153

【讨论】:

  • 我收到的是513
  • @RajRajeshwarSinghRathore 很高兴知道。我的回答是基于 Java 7 的实现细节,因此几乎随时都可能失效。
【解决方案2】:

根据文档,HashSet 不保证任何顺序概念,因此您所看到的很可能在 Java 的未来更新中发生变化。

但是,如果您想知道为什么 Java(截至目前)特定的 HashSet 实现会产生您所看到的结果:这是因为值 1Integer 散列到内部条目中的某个位置HashMap 的表 2 散列到的位置之前(请注意,HashSet 实际上由具有任意值的 HashMap 支持)。这是有道理的,因为Integer 对象的哈希码就是它的值。

事实上,即使你添加更多的数字也可以看到这一点(在一定范围内:入口表的大小,默认为16):

Set<Integer> set = new HashSet<>();
set.add(2);
set.add(1);
set.add(4);
set.add(3);
set.add(0);
System.out.println(set);
[0, 1, 2, 3, 4]

HashSet 的迭代是通过对内部条目表的迭代来实现的,这意味着表中较早的项目排在第一位。

【讨论】:

    【解决方案3】:

    HashSet 是一个无序的集合。它没有保证,也没有“排序”的概念。有关详细信息,请参阅此答案:What is the difference between Set and List?

    如果您需要有序、有序的集合,可以考虑使用TreeSet

    还有一个LinkedHashSet 表示未排序的有序集合。

    【讨论】:

    • @superEb 我实际上只是在我的回复中添加了那个简介。看来我们同时意识到了!
    【解决方案4】:

    java 中的set 不应该是有序列表。请改用ArrayList。另请查看 Java Collection API 以获取更多参考。

    【讨论】:

    • 如果您想要快速(恒定时间)查找但具有可预测的迭代顺序,LinkedHashSet 通常是更好的选择。如果您想节省空间,并且可以容忍慢速(线性时间)查找,请仅使用 ArrayList
    • @Ashwin 请注意,您可以使用Collections.binarySearch() 方法获得排序列表的对数时间 O(log n) 查找时间。
    【解决方案5】:

    经过多次尝试和错误得出结论。这纯粹基于散列顺序。这就是我们称之为 HASH 集的原因。散列基于输入的长度。尝试 4 个单数和 4 个双数。你会得到结果。

    【讨论】:

      猜你喜欢
      • 2013-03-10
      • 1970-01-01
      • 1970-01-01
      • 2018-10-30
      • 2021-09-20
      • 2019-04-07
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多