从 TreeSet 中删除元素时出现问题

发布于 2024-08-26 11:08:52 字数 1484 浏览 3 评论 0原文

我正在执行以下操作

class RuleObject implements Comparable{



    @Override
    public String toString() {
        return "RuleObject [colIndex=" + colIndex + ", probability="
                + probability + ", rowIndex=" + rowIndex + ", rule=" + rule
                + "]";
    }
    String rule;
    double probability;
    int rowIndex;

    int colIndex;

    public RuleObject(String rule, double probability) {
        this.rule = rule;
        this.probability = probability;
    }
    @Override
    public int compareTo(Object o) {

        RuleObject ruleObj = (RuleObject)o;
        System.out.println(ruleObj);
        System.out.println("---------------");
        System.out.println(this);
        if(ruleObj.probability > probability)
            return 1;
        else if(ruleObj.probability < probability)
            return -1;
        else{
            if(ruleObj.colIndex == this.colIndex && ruleObj.rowIndex == this.rowIndex && ruleObj.probability == this.probability && ruleObj.rule.equals(this.rule))
                return 0;
        }
        return 1;

    }


}

并且我有一个包含 RuleObject 元素的 TreeSet。 我正在尝试执行以下操作:

System.out.println(sortedHeap.size());
        RuleObject ruleObj = sortedHeap.first();
        sortedHeap.remove(ruleObj);
System.out.println(sortedHeap.size());

我可以看到集合的大小保持不变。我无法理解为什么它不被删除。 另外,在删除时我可以看到调用了compareTo 方法。但它只被调用了 3 个对象,而 set 中有 8 个对象。 谢谢

I am doing the following

class RuleObject implements Comparable{



    @Override
    public String toString() {
        return "RuleObject [colIndex=" + colIndex + ", probability="
                + probability + ", rowIndex=" + rowIndex + ", rule=" + rule
                + "]";
    }
    String rule;
    double probability;
    int rowIndex;

    int colIndex;

    public RuleObject(String rule, double probability) {
        this.rule = rule;
        this.probability = probability;
    }
    @Override
    public int compareTo(Object o) {

        RuleObject ruleObj = (RuleObject)o;
        System.out.println(ruleObj);
        System.out.println("---------------");
        System.out.println(this);
        if(ruleObj.probability > probability)
            return 1;
        else if(ruleObj.probability < probability)
            return -1;
        else{
            if(ruleObj.colIndex == this.colIndex && ruleObj.rowIndex == this.rowIndex && ruleObj.probability == this.probability && ruleObj.rule.equals(this.rule))
                return 0;
        }
        return 1;

    }


}

And I have a TreeSet containing elements of RuleObject.
I am trying to do the following :

System.out.println(sortedHeap.size());
        RuleObject ruleObj = sortedHeap.first();
        sortedHeap.remove(ruleObj);
System.out.println(sortedHeap.size());

I can see that the size of set remains same. I am not able to understand why is it not being deleted.
Also while deleting I could see compareTo method is called. But it is called for only 3 object whereas in set there are 8 objects.
Thanks

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

唐婉 2024-09-02 11:08:52

查看 删除

从该集合中删除指定元素(如果存在)。更正式地说,如果该集合包含这样的元素,则删除 e 使得 (o==null ? e==null : o.equals(e))

您的问题是 RuleObject@Override equals(Object other)。您需要这样做,当然,您还需要@Override hashCode()


此外,compareTo 被调用的次数少于元素数量的原因是因为它应该是一个 O(log N) 操作;这就是使用 TreeSet 的全部目的。如果您有 1024 个元素,则 compareTo 的调用次数预计不会超过 10 次。


正如弗拉德指出的那样,你的比较器坏了。具体来说,最后一个语句 return 1; 破坏了它。您应该根据其他字段扩展相等的概率情况以返回 -1、0、+1。

Look at the specification for remove:

Removes the specified element from this set if it is present. More formally, removes an element e such that (o==null ? e==null : o.equals(e)), if this set contains such an element.

Your problem is that RuleObject does not @Override equals(Object other). You need to do that, and of course, with that you also need to @Override hashCode().


Also, the reason why compareTo is being called fewer times than the number of elements is because it's supposed to be a O(log N) operation; that's the whole purpose of using TreeSet. If you have 1024 elements, you can expect compareTo to be called no more than 10 times.


As Vlad points out, your comparator is broken. Specifically, the last statement return 1; breaks it. You should expand the equal probability case to return -1, 0, +1 depending on the other fields.

时常饿 2024-09-02 11:08:52

正如polygenelubricants 所指出的,您必须在RuleObject 上实现equals

此外,您的 比较器 本质上是破碎的。它不会强加 总排序,即在某些情况下,它会声明 RuleObject a 既大于又小于另一个 RuleObject b (例如,如果 a.probability= =b.probabilitya.colIndex != b.colIndex。)这将导致在树插入、遍历等过程中出现不需要的行为

。最后,compareTo 还必须与equals一致,即

C 类的自然排序是
表示与 equals 一致 if
并且仅当 (e1.compareTo((Object)e2)
== 0) 对于每个 e1 和 e1.equals((Object)e2) 具有相同的布尔值
C 类的 e2。注意 null 不是
任何类的实例,以及
e.compareTo(null) 应该抛出一个
NullPointerException 即使
e.equals(null) 返回 false。

如果您不关心 RuleObject 的顺序,请使用 HashSet

否则(即您想要以明确定义的方式迭代 TreeSet,例如优先级、顺序),请实现 Comparable 以考虑所有感兴趣的字段,例如:

public int compareTo(Object o) {
  RuleObject r = (RuleObject)o;
  // assume no nulls for now, but you should eventually check
  // also assume o is always of type RuleObject for now,
  //  but you should eventually check
  return
    priority < r.priority ? -1 :
    priority > r.priority ? 1 :
    colIndex < r.colIndex ? -1 :
    colIndex > r.colIndex ? 1 :
    rowIndex < r.rowIndex ? -1 :
    rowIndex > r.rowIndex ? 1 : 0;
}

boolean equals(Object o) {
  // Delegate to compareTo(); no code duplication, consistent.
  return compareTo(o) == 0;
}

As polygenelubricants indicated, you must implement equals on your RuleObjects.

Moreover, your comparator is essentially broken. It does not impose total ordering, i.e. in certain cases it will claim that a RuleObject a is both greater than and less than another RuleObject b (e.g. if a.probability==b.probability and a.colIndex != b.colIndex.) This will result in unwanted behaviour during tree insertion, traversal etc.

In the end, compareTo must also be consistent with equals, i.e.

The natural ordering for a class C is
said to be consistent with equals if
and only if (e1.compareTo((Object)e2)
== 0) has the same boolean value as e1.equals((Object)e2) for every e1 and
e2 of class C. Note that null is not
an instance of any class, and
e.compareTo(null) should throw a
NullPointerException even though
e.equals(null) returns false.

If you do not care about RuleObjects ordering, use a HashSet.

Otherwise (i.e. you want to iterate over the TreeSet in a well defined, e.g. priority, order), implement Comparable to take into account all fields of interest, e.g.:

public int compareTo(Object o) {
  RuleObject r = (RuleObject)o;
  // assume no nulls for now, but you should eventually check
  // also assume o is always of type RuleObject for now,
  //  but you should eventually check
  return
    priority < r.priority ? -1 :
    priority > r.priority ? 1 :
    colIndex < r.colIndex ? -1 :
    colIndex > r.colIndex ? 1 :
    rowIndex < r.rowIndex ? -1 :
    rowIndex > r.rowIndex ? 1 : 0;
}

boolean equals(Object o) {
  // Delegate to compareTo(); no code duplication, consistent.
  return compareTo(o) == 0;
}
堇色安年 2024-09-02 11:08:52

如果您希望它正常工作™,请尝试 Apache 的 CompareToBuilderHashCodeBuilder 和 EqualsBuilder。我提供了示例代码,可以从下面开始。您当然不必采取这条路线,但我认为您会发现它简化了事情。请注意不同函数之间的一致模式。

public int compareTo(Object o) {
  RuleObject ruleObj = (RuleObject) o;
  return new CompareToBuilder()
    .append(this.probability, ruleObj.probability)
    .append(this.colIndex, ruleObj.colIndex)
    .append(this.rowIndex, ruleObj.rowIndex)
    .append(this.rule, ruleObj.rule)
    .toComparison();
}

public int hashCode() {
  // You should customize the hard-coded numbers, as described in the docs.
  return new HashCodeBuilder(17, 37).
    append(probability).
    append(colIndex).
    append(rowIndex).
    append(rule).
    toHashCode();
}

public boolean equals(Object obj) {
  if (obj == null) { return false; }
  if (obj == this) { return true; }
  if (obj.getClass() != getClass()) {
    return false;
  }
  RuleObject rhs = (RuleObject) obj;
  return new EqualsBuilder()
    .append(probability, rhs.probability)
    .append(colIndex, rhs.colIndex)
    .append(colIndex, rhs.colIndex)
    .append(rule, rhs.rule)
    .isEquals();
}

If you want it to Just Work™, try Apache's CompareToBuilder, HashCodeBuilder, and EqualsBuilder. I have provided sample code to start from below. You certainly don't have to take this route, but I think you will find it simplifies things. Note the consistent pattern between the different functions.

public int compareTo(Object o) {
  RuleObject ruleObj = (RuleObject) o;
  return new CompareToBuilder()
    .append(this.probability, ruleObj.probability)
    .append(this.colIndex, ruleObj.colIndex)
    .append(this.rowIndex, ruleObj.rowIndex)
    .append(this.rule, ruleObj.rule)
    .toComparison();
}

public int hashCode() {
  // You should customize the hard-coded numbers, as described in the docs.
  return new HashCodeBuilder(17, 37).
    append(probability).
    append(colIndex).
    append(rowIndex).
    append(rule).
    toHashCode();
}

public boolean equals(Object obj) {
  if (obj == null) { return false; }
  if (obj == this) { return true; }
  if (obj.getClass() != getClass()) {
    return false;
  }
  RuleObject rhs = (RuleObject) obj;
  return new EqualsBuilder()
    .append(probability, rhs.probability)
    .append(colIndex, rhs.colIndex)
    .append(colIndex, rhs.colIndex)
    .append(rule, rhs.rule)
    .isEquals();
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文