Java 在树集中交换密钥?

Java 在树集中交换密钥?,java,hashset,treeset,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)

假设我有这个班:

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

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

这样做会“破坏”结构,还是一切都会继续正常工作

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

//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);
}
从文件中:

请注意,由集合维护的顺序(无论是否为显式 如果提供比较器,则必须与equals一致 正确实现Set接口

您的
节点
类“
可比
实现与
等于
不一致。(
compareTo
可以为两个不相等的
节点
实例返回
0

这本身使您的
节点
类不适合作为
树集
的元素

即使是提议的解决办法也不够

您可能会试图通过基于节点中包含的值实现
equals()
(和
hashCode()
)来解决此问题。但没有用,因为这会违反通用接口文档上的警告:

注意:如果将可变对象用作集合,则必须非常小心 元素。如果 对象的更改方式会影响equals比较,而 对象是集合中的一个元素。这是一个特例 禁止是指不允许集合包含自身 作为一个元素

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


然而,最简单的解决方案似乎是完全放弃
可比
接口,不实现
equals
hashCode
,只使用
HashSet
而不是
TreeSet
。在这种情况下,您可以更改节点的内容,而不会影响邻居集的正常运行。

这将破坏结构。键应该是不可变的。Hashcode作为键添加后无法更改。@PiotrGwiazda感谢您的回答。那么我刚才发布的解决方案呢?@JonnyHenly在您发布评论时进行了编辑。为什么要交换节点的键并改变结构,而您只需交换它们的值而不改变结构?一个节点将有多少个邻居?也许你可以只使用一个列表而不是一套。谢谢你的评论。你是说我也必须实现
equals
吗?
HashSet
不幸的是,这不是一个选项,因为我经常使用
tailSet
headSet
来计算topK,正如前面解释的那样,你必须使用不可变节点。这将需要在图形中替换它们,而不是更改它们的内容。或者使用
HashSet
,在算法中本地使用
比较器创建一个
TreeSet
,以查找k个最近的节点。
//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);
}