假设我有这门课程:
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);
}
答案 0 :(得分:1)
来自TreeSet
文档:
注意由一组维护的排序(无论是否显式 比较器提供)必须与equals一致,如果是的话 正确实现Set接口。
您的Node
课程&#39; Comparable
实施与equals
不一致。 (compareTo
可以针对两个不相等的0
个实例返回Node
。
这本身就使您的Node
课程不适合成为TreeSet
的元素。
即使是建议的解决方法也不够。
您可能希望通过将equals()
(和hashCode()
)实现为基于节点中包含的值来解决此问题。但无济于事,因为这会对一般Set界面的文件发出警告:
注意:如果将可变对象用作set,则必须非常小心 元素。如果a的值,则不指定集合的行为 对象以影响等于比较的方式改变 对象是集合中的元素。这是一个特例 禁止的是,一套装置不允许包含自己 作为一个元素。
因此,添加equals和hashCode仍然不够:您的实例也必须是不可变的。
然而,最简单的解决方案似乎是完全放弃Comparable
界面,不实施equals
和hashCode
,只使用HashSet
代替TreeSet
。在这种情况下,您可以更改节点的内容,而不会影响邻居集的正常运行。