Java Collections API HashSet 删除方法
我在使用 Java Collections API 时遇到了这个问题。基本上,这是用于实现 Kruskal 算法(用于查找 MST)的支持方法。我创建这个类是为了实现并集/查找算法。
我的问题是,因为我能够找到解决方法,所以有人知道“union”方法中的删除方法不能一致工作的原因吗?也就是说在运行时它会删除一些元素而不是其他元素。例如,我为一项涉及城市的任务实现了这一点,它似乎不喜欢删除一些城市。特别是它反复偶然发现几个不同的集合,但总是相同的。我想知道这是否是一个对象引用问题,即我是否测试了错误的东西,但我无法解决它。
我知道我的其余工作是正确的,因为我能够用消除该元素的循环替换它,并且算法完美执行。然而,性能可能稍差一些。
我想知道是否有人能看到错误。另外我应该注意,我从不同的类调用它,但是,调用是使用使用 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;
I encountered this issue while working with the Java Collections API. Basically this is a support method for an implementation of Kruskal's algorithm for finding an MST. I created this class for implementing the union/find algorithm.
My question, as I was able to find a work around, is that does anybody know of any reason why the remove method in the "union" method would not work consistently. That is at run time it would remove some elements and not others. For example I implemented this for a task involving cities and it seemed to not like removing some cities. In particular it repeatedly stumbled on a couple of different sets, but always the same ones. I wondered whether it was a object reference issue, i.e. whether I was testing the wrong thing, but I could not get around it.
I know the rest of my work was correct as I was able to replace it with a loop that eliminated the element, and the algorithm executed perfectly. Probably with slightly worse performance, however.
I was wondering whether anybody can see a mistake. Also I should note that I called it from different class, however, the calls were made with elements that were retrieved using the find method. Note that the find method must work well, since simply altering the remove method made the whole thing work, i.e. it was finding and returning the appropriate objects.
Thanks
Oscar
/*
* 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);
}
}
And I replaced it with
HashSet<HashSet<String>> temp = new HashSet<HashSet<String>>();
for(HashSet<String> f: underlying)
{
if(f != h2)
{
temp.add(f);
}
}
underlying = temp;
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
问题是,当您修改嵌套 HashSet 之一的内容时,就会搞砸外部 HashSet 的内部(因为嵌套 HashSet 的 hashCode() 已更改)。为了正确维护这个集合,每当您想要修改其中一个嵌套的 HashSet 时,您必须首先将其从外部 HashSet 中删除,然后重新添加它(如果需要)。
(您确实没有提供足够的代码来确定这是否确实是问题所在,但这是我最好的猜测)。
The problem is that when you modify the contents of one of the nested HashSets, you screw up the internals of the outer HashSet (because the hashCode() of the nested HashSet has changed). in order to maintain this collection correctly, whenever you want to modify one of the nested HashSets you must first remove it from the outer HashSet and then re-add it (if necessary).
(you don't really provide enough code to figure out if that's truly the problem, but that's my best guess).
跟进@jtahlborn的回答,
AbstractSet.hashCode()
说演示 @jtahlborn 答案(正确)的代码
输出
添加到列表中以尽可能使用不可变集合的又一个原因。
Following up on @jtahlborn's answer, the contract for
AbstractSet.hashCode()
saysCode to demonstrate @jtahlborn's answer (which is correct)
Outputs
One more reason to add to the list to make use of immutable collections wherever possible.