在TreeSet中交换密钥?

时间:2017-06-14 17:20:00

标签: java hashset treeset

假设我有这门课程:

public class Node implements Comparable<Node>{
  public float key;
  public TreeSet<Node> neighbors;

  public Node{
    //fill neighbors somehow
  }

  @Override
  public int compareTo(Node n) {
    if(this.key == n.key)
        return 0;
    else if(this.key > n.key)
        return 1;
    else
        return -1;
  }

}

因此,这是图的经典节点,其中每个节点连接到一组节点(即其邻居)。我使用TreeSet因为我经常(经常)知道所有邻居的密钥大于(小)某个值。现在,让我们假设我有这种方法:

//swap nodes keys
void swapKeys(Node a, Node b){
  float ak = a.key;
  a.key = b.key;
  b.key = ak; 
}

请注意,此方法仅更改两个节点键,仅此而已。

这样做&#34;打破&#34;结构,还是一切都会继续正常工作?

如果这打破了结构,那么这个简单的解决方案呢:

//swap nodes keys
void swapKeys(Node a, Node b){
  a.remove(b);
  b.remove(a);
  float ak = a.key;
  a.key = b.key;
  b.key = ak; 
  a.add(b);
  b.add(a);
}

1 个答案:

答案 0 :(得分:1)

来自TreeSet文档:

  

注意由一组维护的排序(无论是否显式   比较器提供)必须与equals一致,如果是的话   正确实现Set接口。

您的Node课程&#39; Comparable实施与equals不一致。 (compareTo可以针对两个不相等的0个实例返回Node

这本身就使您的Node课程不适合成为TreeSet的元素。

即使是建议的解决方法也不够。

您可能希望通过将equals()(和hashCode())实现为基于节点中包含的值来解决此问题。但无济于事,因为这会对一般Set界面的文件发出警告:

  

注意:如果将可变对象用作set,则必须非常小心   元素。如果a的值,则不指定集合的​​行为   对象以影响等于比较的方式改变   对象是集合中的元素。这是一个特例   禁止的是,一套装置不允许包含自己   作为一个元素。

因此,添加equals和hashCode仍然不够:您的实例也必须是不可变的。

然而,最简单的解决方案似乎是完全放弃Comparable界面,不实施equalshashCode,只使用HashSet代替TreeSet。在这种情况下,您可以更改节点的内容,而不会影响邻居集的正常运行。