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

时间:2010-03-21 02:27:27

标签: java set

我正在做以下

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个对象,而在集合中则有8个对象。 感谢

3 个答案:

答案 0 :(得分:4)

polygenelubricants所示,您必须在equals上实施RuleObject

此外,您的comparator基本上已被破坏。它没有强加total ordering,即在某些情况下它会声称RuleObject a大于和小于另一个RuleObject b(例如,如果a.probability == b.probabilitya.colIndex!= b.colIndex。)这会在树插入,遍历等过程中导致不必要的行为。

最后,compareTo must also be consistent with equals,即

  

C类的自然顺序是   据说与ifals一致   并且仅当(e1.compareTo((Object)e2)   == 0)对于每个e1和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;
}

答案 1 :(得分:4)

查看remove的规范:

  

从该集合中删除指定的元素(如果存在)。更正式地,如果此集合包含此类元素,则删除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;打破了它。您应该扩展相等的probability大小写以返回-1,0,+ 1,具体取决于其他字段。

答案 2 :(得分:0)

如果您想要Just Work™,请尝试Apache的CompareToBuilderHashCodeBuilderEqualsBuilder。我已经提供了从下面开始的示例代码。你当然不必采取这种方式,但我认为你会发现它简化了事情。注意不同功能之间的一致模式。

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();
}