TreeSet不会遍历整个集合以进行删除 - 已覆盖可比较

时间:2016-03-17 05:42:44

标签: java iterator override comparable treeset

我的treeset.remove()SOMETIMES正常工作。但有时它不会遍历搜索匹配的所有元素,因此它不会删除我正在搜索的元素。下面是我对treeset compareTo的重写。

public class Entry implements Comparable<Entry>{
    String oid, sd;
    double p;
    int sz, time;
    public Entry(int time, String Order_id, String side, double price, int size){
    this.oid = Order_id;
    this.sd = side;
    this.p = price;
    this.sz = size;
    this.time = time;
    }
    @Override
    public int compareTo(Entry other) {
        if(this.oid.equals(other.oid))
                return 0;
        if (this.p > other.p)
            return 1;
        if (this.p < other.p)
            return -1;
        if(this.p == other.p){
            if(this.sd.equals(other.sd)){
                if(this.sd.equals("S"))
                    return ((this.sz >= other.sz) ? 1 : -1);
                if(this.sd.equals("B"))
                    return ((this.sz >= other.sz) ? -1 : 1);
                else{
                    if(other.sd.equals("S"))
                        return -1;
                    else
                        return 1;
                }

             }
        }
        return 1;
    }
}

在这种情况下,它会迭代大约一半的集合并停止一个条目,而不是需要删除的位置,但它返回的所有值都是1.

2 个答案:

答案 0 :(得分:0)

首先,这是一个非常糟糕的compareTo()实现。您不应将thisotherS等常量进行比较。你必须将它们相互比较。

我建议你阅读compareTo()的用法。

也许你可以改变你的compareTo():

public int compareTo(Entry other)
{
     if(this.oid.compareTo(other.oid) < 0)
         return -1;
     else if(this.oid.compareTo(other.oid) > 0)
         return 1;
     else
     {
        if (this.p > other.p)
            return 1;
        else if (this.p < other.p)
            return -1;
        else
            return 0;
      }
}

仅仅是为了灵感,我并不是要完全按照这种方式实施。我也不知道你想要达到的目标。

答案 1 :(得分:0)

您的比较功能不是正确的比较功能。为了使比较功能起作用,它必须遵循总排序的数学规则。基本上,这意味着:x == x; x == y当且仅当y == x时,x&lt; y当且仅当y> x时;如果x == y和y == z,那么x == z;如果x&lt; y且y&lt; z则x&lt; z;同样适用于&gt;。

你的功能在最后一点,传递性上失败了。该功能看起来很奇怪,也可能在其他点上失败,但分析起来有点困难。但要表明它不具有传递性:假设对象A具有oid=="x"p==1.0;对象B有oid=="y"p==2.0;对象C有oid=="x"p==3.0A.compareTo(B)将返回1,因为oid是不相等的并且1.0&lt; 2.0。 B.compareTo(C)将返回1,因为oid是不相等的并且2.0&lt; 3.0。因此,传递规则意味着A.compareTo(C)必须返回1.但是你的函数返回0,因为如果oid是相等的,它总是返回0。所以你的功能不遵守规则。由于TreeSet之类的算法依赖于比较函数是一个有效的比较函数,如果你给它一些不符合规则的东西,它们的行为是不可预测的。

更新:由于我现在对你想要达到的目标有更好的想法(我的评论),我想我可以指出出了什么问题。

代码的第一部分似乎表达了这样的想法:“如果订单ID相同,则两个对象是相同的,否则我们将按价格排序”。您已经澄清过,如果ID相同,价格将相同。我可能会进行检查以确保,否则TreeSet算法将返回可疑结果:

    if(this.oid.equals(other.oid)) {
        if (this.p != other.p) {
            throw new IllegalArgumentException("Orders with same ID but different price");
        }
        return 0;
    }

这可以捕获你程序其余部分的错误。

好的,我们知道订单ID不同。你想按价格排序。如果多个条目具有相同的价格(并且都是不同的订单),那么:一些项目将具有sd = S而一些项目将具有sd = B.看起来你想要按大小按升序对S进行排序,按大小按降序对B进行排序。但S和B本身在哪里?

你需要决定:要么首先想要S,要么想要B,或者你想要先是B,然后是S。 (如果你想要比这更复杂的东西,你必须自己解决。)你编码的方式,如果一个对象是S而另一个是B(当价格相等时),你总是返回1.因此,如果两个对象X和Y具有相同的价格,但是不同的sd字段,X.compareTo(Y)返回1,Y.compareTo(X)返回1.这意味着X必须在Y之后,Y必须来在X之后。这不起作用。

因此,如果this.sd.equals(other.sd.equals)为假,那么您需要添加的第一件事就是更多逻辑。您需要String.compareTo()或其他一些机制来确保B始终位于S之前,或者S始终位于B之前,无论您选择哪个。这可能是导致问题的重大错误。

仔细阅读后,您可能实际上已尝试使用代码

进行此操作
            else{
                if(other.sd.equals("S"))
                    return -1;
                else
                    return 1;

如果它在正确的地方,它将完成你需要完成的事情。不幸的是,它附加在错误的if上。如果sd不相等,则else部分需要发生。你需要修复花括号。并且,为了避免这样的事故,在if语句中始终使用花括号是有帮助的,即使if的主体只是一个语句。所以我想你问题的答案是:是的,问题是由于你的语法很差。

下一个错误就在这里:

return ((this.sz >= other.sz) ? 1 : -1);

如果左参数较大,则compareTo()函数应返回正整数,如果左参数较小则返回负整数,如果它们相等则返回0。但是你永远不会在这里回归0。这意味着如果您必须使用不同订单ID,但价格,价格,尺寸和尺寸相同的条目,您将再次达到X.compareTo(Y)为1且Y.compareTo(X)也为1的情况,这不应该是发生。如果所有尺寸不同,这可能不会导致您的错误。但依赖于此仍然是不好的做法。您需要确保检查大小是否相等,如果它们相等则返回0。这里有一个Integer.compareTo(int1, int2)函数,因此您不必使用重复的?:运算符。