我在使用Java Collections API时遇到了这个问题。基本上,这是用于实现Kruskal用于查找MST的算法的支持方法。我创建了这个类来实现union / find算法。
我的问题,因为我能够找到一个解决方法,是否有人知道为什么“union”方法中的remove方法不能一致地工作的任何原因。那是在运行时它将删除一些元素而不是其他元素。例如,我实现了这个涉及城市的任务,似乎不喜欢删除一些城市。特别是它偶然发现了几个不同的集合,但总是相同的集合。我想知道它是否是一个对象引用问题,即我是否测试了错误的东西,但我无法解决它。
我知道我的其余工作是正确的,因为我能够用消除元素的循环替换它,并且算法执行得非常完美。但是,可能表现稍差一些。
我想知道是否有人能看到错误。另外我应该注意我从不同的类调用它,但是,调用是使用find方法检索的元素。请注意,find方法必须正常工作,因为只需更改remove方法就可以完成所有工作,即它正在查找并返回相应的对象。
由于
的奥斯卡
/*
* A constructor for creating a new object of this class.
*/
DisjointSets()
{
underlying = new HashSet<HashSet<String>>();
}
/*
* A method for adding a set to this DisjointSets object
*/
void add(HashSet<String> h)
{
underlying.add(h);
}
/*
* A method for finding an element in this DisjointSet object.
*/
HashSet<String> find(String s)
{
// Check each set in the DisjointSets object
for(HashSet<String> h: underlying)
{
if(h.contains(s))
{
return h;
}
}
return null;
}
/*
* A method for combining to subsets of the DisjointSets
*/
void union(HashSet<String> h1, HashSet<String> h2)
{
System.out.print("CHECK ON DS\n");
System.out.print("*********************\n");
System.out.print("H1 is : { ");
for (HashSet<String> n: underlying)
{
System.out.print("Set is : { ");
for (String h : n)
{
System.out.print(h + " , ");
}
System.out.print("} \n ");
}
// Add the objects of h1 to h2
// DOES NOT WORK CONSISTENTLY
h1.addAll(h2);
underlying.remove(h2);
}
}
我用
代替了它HashSet<HashSet<String>> temp = new HashSet<HashSet<String>>();
for(HashSet<String> f: underlying)
{
if(f != h2)
{
temp.add(f);
}
}
underlying = temp;
答案 0 :(得分:4)
问题在于,当您修改其中一个嵌套HashSet的内容时,会搞砸外部HashSet的内部(因为嵌套HashSet的hashCode()已更改)。为了正确维护这个集合,每当你想修改其中一个嵌套的HashSets时,你必须首先从外部HashSet中删除它,然后重新添加它(如果需要的话)。
(你真的没有提供足够的代码来确定这是否真的是问题,但这是我最好的猜测。)
Set<Set<String>> outerSet = new HashSet<String>();
Set<String> innerSet = new HashSet<String>();
innerSet.add("foo");
outerSet.add(innerSet);
// *** BROKEN ***
innerSet.add("bar"); // <- adding element to innerSet changes result of innerSet.hashCode()
outerSet.remove(innerSet); // <- this may or may not work because outerSet is _broken_
// *** BROKEN ***
// *** CORRECT ***
outerSet.remove(innerSet);
innerSet.add("bar");
// now you can put innerSet back in outerSet if necessary
答案 1 :(得分:0)
跟随@ jtahlborn的回答,AbstractSet.hashCode()
的合同说
返回此的哈希码值 组。定义了集合的哈希码 是哈希码的总和 集合中的元素。这确保了 s1.equals(s2)意味着 s1.hashCode()== s2.hashCode()for any 根据需要设置两组s1和s2 Object.hashCode的一般合约。
此实现枚举结束 set,调用hashCode方法 在集合中的每个元素上,和 将结果加起来。
演示@ jtahlborn答案的代码(这是正确的)
import java.util.HashSet;
import java.util.Set;
public class TestHashSetHashCode {
public static void main(String[] args)
{
Set<String> strings = new HashSet<String>();
strings.add("one");
strings.add("two");
strings.add("three");
strings.add("four");
strings.add("five");
Set<String> test = new HashSet<String>();
System.out.println("Code "+test.hashCode());
for (String s : strings) {
test.add(s);
System.out.println("Code "+test.hashCode());
}
}
}
输出
Code 0 Code 115276 Code 3258622 Code 3368804 Code 113708290 Code 116857384
添加到列表中以便尽可能使用不可变集合的另一个原因。