我的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.
答案 0 :(得分:0)
首先,这是一个非常糟糕的compareTo()实现。您不应将this
或other
与S
等常量进行比较。你必须将它们相互比较。
我建议你阅读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.0
。 A.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)
函数,因此您不必使用重复的?:
运算符。