代码之家  ›  专栏  ›  技术社区  ›  dvim

Java树集容器()给出错误的结果

  •  1
  • dvim  · 技术社区  · 14 年前

    我正在尝试用Java编写一点数学。我想做的是 循环陪集 去树下。陪集有一个索引和一组整数。如果集合具有相同的元素,则coset等于其他coset。如果集合不同,那么coset按其索引排序。

    例如:

    C1 = [1, 2, 4, 8]
    C3 = [3, 6, 9, 12]
    C9 = [3, 6, 9, 12]
    
    C1 is less than C3
    C3 is equal to C9
    

    数学够了。我选择将coset放到treeset,因为我不需要重复的元素,我需要按索引对它们进行排序。

    问题甚至是treeset.contains()返回false,我仍然可以在treeset中找到一个元素,当使用compareto()和equals()方法时,它是相等的。

    这是程序的实际打印输出:

    cosets = [C0, C1, C3, C5, C7]
    cosets.contains(C9) = false
    C0.compareTo(C9) = -1, C0.equals(C9) = false
    C1.compareTo(C9) = -1, C1.equals(C9) = false
    C3.compareTo(C9) = 0, C3.equals(C9) = true
    C5.compareTo(C9) = -1, C5.equals(C9) = false
    C7.compareTo(C9) = -1, C7.equals(C9) = false
    

    我附上下面的代码。我不想把代码简化,因为我发现它有魔力。如果你改变 魔力指数 代码中的值小于等于7,它开始工作。在我看来,这就像是一个JVM bug。

    http://2m.lt/files/Main.java

    http://2m.lt/files/Coset.java

    有什么建议吗?

    3 回复  |  直到 14 年前
        1
  •  3
  •   Peter Lawrey    14 年前

    正如我常说的,如果程序中有错误,请使用调试器。这很快就说明了你的问题。

    Treeset是一个二叉树。在搜索时,它会根据要查找的元素是在它正在检查的元素之前还是之后(或相同的元素)在树中导航。如果您将以下内容添加到CompareTo()中,

    System.out.println("Comparing, "+this+" to "+c);
    

    它会打印出来的

    Comparing, C9 to C1
    Comparing, C9 to C5
    Comparing, C9 to C7
    

    问题是,C9在它不匹配的每个元素之后。所以当它到达树上的c5时,你的compareto会说它在后面,当它实际上需要向前看(到达c3)并且搜索沿着树的错误路径进行时。

        2
  •  4
  •   Michael Borgwardt    14 年前

    你的 compareTo() equals() 方法不一致,因此 TreeSet 无法正确使用它们。

    来自 API doc :

    请注意,由 设置(无论是否显式 必须提供比较器 与等号一致 正确实现设置接口。 (参见比较或比较器 精确定义符合 等于。)这是因为集合 接口是根据 等于运算,但等于树集 实例执行所有元素 使用其比较器进行比较(或 比较)方法,所以两个元素 通过这种方法被认为是相等的, 从集合的角度来看,相等。 集合的行为定义良好 即使它的顺序不一致 平等;它只是不服从 设置接口的总承包。

        3
  •  3
  •   Tom Hawtin - tackline    14 年前

    你的 Comparable 实施于 Coset 不提供总排序。

    看起来您应该在 value TreeSet . 检查之前或之后 index .