我有以下代码:
Set<Set<Integer>> groups = new HashSet<>();
for (int[] edge : edges) {
Set<Integer> match1 = null;
Set<Integer> match2 = null;
for(Set<Integer> group : groups) {
if(group.contains(edge[0])) match1 = group;
if(group.contains(edge[1])) match2 = group;
}
if(match1 != null && match1 == match2) {
result = edge;
}else if(match1 != null && match2 != null && match1 != match2) {
match1.addAll(match2);
groups.remove(match2); <---- This does not remove match2 from set
}else{
Set<Integer> newGroup = new HashSet<>();
newGroup.add(edge[0]);
newGroup.add(edge[1]);
groups.add(newGroup);
}
.........
}
groups
是一组整数。
但是,groups.remove(match2(方法不会从组中删除整数集。
这里发生了什么?
引用Set
接口文档:
注意:如果可变对象用作集合元素,则必须格外小心。当对象是集合中的元素时,如果对象的值以影响相等比较的方式更改,则不指定集合的行为。这种禁止的一个特殊情况是,不允许集合将自己作为元素包含。
当match1
仍在外部Set
中时,使用addAll()
调用对其进行变异,这违反了此规则。这种突变会导致哈希代码在外部Set
不知情的情况下发生更改,因此内部Set
现在位于错误的哈希桶中,当您试图在后续迭代中删除它时,无法找到它。
作为一种变通方法,您可以删除它,然后调用addAll()
,然后再次添加它。在内部,这将导致它被放置在新哈希代码的正确哈希桶中。
顺便说一句,看起来你正在实现一个连接组件检测算法。使用不相交的集合林数据结构可以更有效地执行此操作。在如何将每个集合存储在不相交的集合林中,有一些很好的伪代码。