java - Set 的内部顺序怎么会被破坏呢?

标签 java data-structures set

每个 Java 文档都说 Set 是无序数据结构。 但是当我们尝试这样的实验时:

public class SetTest {

    @Test
    public void testIterationsOverSet() {
        Set<Integer> s = new HashSet<>();


        for (int i = 0; i < 10; i++) {
            s.add(i);
            System.out.println(Arrays.toString(s.toArray()));
        }

        Set<Integer> s2 = new LinkedHashSet<>(s);

        Set<Integer> s3 = new TreeSet<>(s2);

        printSet(s, "HashSet");

        printSet(s2, "LinkedHashSet");

        printSet(s3, "TreeSet");

    }

    private void printSet(Set<Integer> set, String msg) {
        System.out.println("\n"+msg);
        Iterator<Integer> itr = set.iterator();
        while (itr.hasNext()) {
            System.out.print(itr.next());
        }
        System.out.println();
    }
}

我们将得到如下输出:

[0]
[0, 1]
[0, 1, 2]
[0, 1, 2, 3]
[0, 1, 2, 3, 4]
[0, 1, 2, 3, 4, 5]
[0, 1, 2, 3, 4, 5, 6]
[0, 1, 2, 3, 4, 5, 6, 7]
[0, 1, 2, 3, 4, 5, 6, 7, 8]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

HashSet
0123456789

LinkedHashSet
0123456789

TreeSet
0123456789

各种集合的顺序是上面输出中的顺序。我有一个假设,每次我们通过添加新元素来更改 Set 时,我们都会崩溃,我们会更改顺序,但所有内容似乎都是在 Set 内部排序的,元素在添加时存储。

所以实际上,据说顺序是不能保证的,上面的例子是正确的,一切都按预期进行。

但问题是,在什么情况下我们可以打破 Set 内部的顺序?

最佳答案

哈希集不会对您插入的数字进行排序,但它恰好在这种特定情况下保留插入顺序,因为您要插入从 0 开始的一组连续数字。纯属偶然,这组数字最终没有被打乱。

原因是整数的哈希码是整数本身,哈希码直接映射到 HashMap 内部数组中的索引。 0 插入到索引 0 处,1 插入到索引 1 处,2 插入到索引 2 处,依此类推。当您插入连续的小整数时,您实际上是在测试最简单的可能场景,其中 HashMap 的行为实际上是可以预测的。

尝试更复杂的场景:代替0-9,插入100-109;或 100-200,步长为 10;或 200-100,步长为 -10;或一组具有不同大小间隙和顺序的不同数字,例如 {100, 2, 2222, -63, 72};等等

此外,看看 HashSet<String> 会发生什么与 HashSet<Integer> 相比。我预计,您会发现字符串的排序非常随意,而且很少按顺序排列。

关于java - Set 的内部顺序怎么会被破坏呢?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59552418/

相关文章:

java - 使用 TokensRegex 开发基于规则的 NER 并根据上下文单词对实体进行分类

java - SecureRandom 中 nextXXX() 和 generateSeed() 函数之间的区别?

java - 如何设置连接等待提醒?

python - 在 pdist 压缩距离矩阵中找到最小值的索引

data-structures - 如何在不需要分配给新变量的情况下为链表实现前置?

java - 替换 HashSet Java 成员

java - Android 上的 JXTA 应用程序

interface - 是否可以在接口(interface)定义中使用 getter/setter?

java - 根据条件从 List<Object> 中删除重复项

c# - 根的红黑树删除