为什么在尝试对该图进行 DFS 时会出现 StackOverFlowError?
我正在尝试编写一种算法来确定图是否连通。我认为我的代码几乎是正确的,尽管我不断收到 StackOverFlowError 错误。我个人认为,因为我正在测试我的算法,图中有一个循环,所以我的代码不理解它并进入循环。但我正在使用一个数组来查看节点是否已被访问!所以这种事不应该发生!无论如何,这是我的代码:
public int isConnected(String s)
{
int in = nodes.indexOf(s);
visited[in] = true;
counter++;
for(int i = 0; i < listOfChildren(s).size(); i++)
{
int ind = nodes.indexOf(listOfChildren(s).get(i));
if(visited[ind] == false)
{
isConnected(listOfChildren(s).get(i));
}
}
System.out.println(counter);
if(counter == nodes.size())
return 1;
return 0;
}
s 是我开始的某个节点,节点是节点的 ArrayList,并且与访问的数组具有相同的大小(在本例中为 5)。一开始访问看起来像这样:[false false false false false],所以没有访问任何节点。 listOfChildren() 返回特定节点的子节点(不是全部,只是与该节点相邻的子节点)的 ArrayList。我确信 listOfChildren() 有效,因为我测试了它 43545454 次。
感谢任何帮助(如果可能的话,对代码进行最小的更改)。谢谢。
更新:
我的图是有向的..
我像这样定义访问:
private boolean[] visited;
并且我在构造函数中将其中的所有内容设置为 false 这段代码:
public void setUnvisited()
{
visited = new boolean[nodes.size()];
for(int i = 0; i < nodes.size(); i++)
{
visited[i] = false;
}
}
节点是字符串!访问过的节点和节点具有相同的长度。这就是为什么我可以使用nodes.indexOf(blabla)来访问数组。
更新2:
图表如下所示:
我确定问题出在 N3 之后,算法在 N3 之后进入循环,因为它不不明白 N1 已经被访问过。我实在不明白为什么会出现这样的情况!
UPDATE3
字符串具有不同的名称,并且没有重复项。例如,indexOf(nodes.get(2)) 给出 2 而不是 0 或其他任何值。
问题是访问后N3 算法应该停止并返回 0 或 1,但我不知道该怎么做:)
I am trying to write an algorithm that determines whether a graph is connected or not. I think my code is almost correct, although I keep getting StackOverFlowError. I personally think because there's a cycle in the graph I'm testing my algorithm with, my code doesn't understand that and comes in a loop. But I'm using an array to see if a node was already visited! So that should not happen! Anyways this is my code:
public int isConnected(String s)
{
int in = nodes.indexOf(s);
visited[in] = true;
counter++;
for(int i = 0; i < listOfChildren(s).size(); i++)
{
int ind = nodes.indexOf(listOfChildren(s).get(i));
if(visited[ind] == false)
{
isConnected(listOfChildren(s).get(i));
}
}
System.out.println(counter);
if(counter == nodes.size())
return 1;
return 0;
}
s is some node I begin with, nodes is an ArrayList of nodes and has the same size(5 in this case) as the array visited. In the beginning visited looks like this: [false false false false false], so none of the nodes was visited. listOfChildren() return an ArrayList of the children(not all of them, just the ones adjacent to the node) of a particular node. I am sure that listOfChildren() works, since I tested it 43545454 times.
Any help is appreciated(with minimum change of the code, if possible). Thanks.
UPDATE:
My graph is directed..
I define visited like this:
private boolean[] visited;
and I set everything in it to false in my constructor this code:
public void setUnvisited()
{
visited = new boolean[nodes.size()];
for(int i = 0; i < nodes.size(); i++)
{
visited[i] = false;
}
}
The nodes are strings! visited and nodes have the same length. That's why I can use nodes.indexOf(blabla) for the array visited.
UPDATE2:
This is how the graph looks like:
I'm sure the problem is after N3, the algorithm goes in a loop after N3, because it doesn't understand that N1 was already visited. I really don't understand why this happens!
UPDATE3
String have different names and there are no duplicates.. so for example indexOf(nodes.get(2)) gives 2 and not 0 or anything else..
The problem is that after visiting N3 the algorithm should stop and return 0 or 1, but I don't know how to do that :)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
您发现这很难追踪的原因是您的图形类中的所有可变状态。特别是,您有
count
和visited
,后者由您的方法isConnected
和setUnvisited
修改。您依靠数组
visited
来告诉您何时停止递归,但在每次递归调用时通过调用listOfChildren
意外地重置了数组。解决这个问题的一种方法是使
visited
不是类成员。这是一个对代码修改很少的解决方案:由于
visited
和counter
不再共享,因此您遇到的错误消失了。这还解决了您遇到的另一个错误(但尚未注意到),其中只有第一个isConnected()
调用有效 - 因为在这种情况下您没有重置 < code>visited 或counter
适当地。与上面相同的想法的更清晰的实现:
我实际上没有尝试编译或运行它,所以可能存在错误,但我希望你明白这个想法。
The reason you found this so difficult to track down is all the mutable state in your graph class. In particular you have
count
andvisited
, the latter being modified by both your methodsisConnected
andsetUnvisited
.You depend on your array
visited
to tell you when to stop recursing, but accidentally reset the array on every recursive call through your call tolistOfChildren
.One way around this to make it so that
visited
is not a class member. Here's a solution which modifies your code very little:Since
visited
andcounter
are no longer shared, the bug you had is gone. This also solves another bug you had (but didn't notice yet) where only the firstisConnected()
call works--because in that case you weren't resettingvisited
orcounter
appropriately.A cleaner implementation of the same idea as above:
I haven't actually tried to compile or run that, so there may be bugs, but you get the idea, I hope.
我根据您的更新制作了一个小测试程序,它似乎很有魅力:
isConnected 方法与您的相同,我只是添加了一些用于记录的消息。输出:
正如预期的那样,该图未连接(它与您在问题上绘制的图相同)。如果我将起始节点更改为 N4 并将 N1 的唯一子节点更改为 N0,则算法会正确地将图识别为已连接。基于此,我想说问题要么是 listOfChildren 返回一些古怪的东西,要么是 visited 使用的索引(在某些时候,visited[in] = true 标记其他一些索引已被访问,而不是 if(visited[ind] == false) 检查它们何时应该相同?)。
I made a small test program based on your updates, and it seems to work like a charm:
The isConnected-method is same as yours, I just added some messages for logging. Output:
As expected, the graph is not connected (it's the same graph you drew on your question). If I change the starting node to N4 and change N1's only child to N0, the algorithm correctly recognizes the graph as connected. Based on this, I'd say the problem is either the listOfChildren returning something wacky or the indices used with visited (at some point, visited[in] = true marks some other index as visited than if(visited[ind] == false) is checking against when they should be the same?).
真正的问题是,您试图用字符串表示节点。通过这样做,您必须将 Node 的子节点存储在其他地方,
listOfChildren
。您还需要跟踪您访问过的人,boolean[] 访问过
。现在可以通过两种方式标识节点
"node1","node2",...
nodes
中的索引。哦哦。现在,您必须确保每个字符串表示形式在节点数组中都只有一个索引。 (两个标识必须是一对一的映射。)
看到问题了吗?存在一个
'node'
具有三个索引,或者存在三个同名节点!也许这不是同一个“节点”,您是指字符串“节点”还是索引“节点”?
要解决此问题,请为节点创建一个标识,一个表示:
不需要字符串或索引!只要让节点成为一个节点即可。
The real problem is, you are trying to represent a Node by a String. By doing that, you have to store the children of a Node somewhere else,
listOfChildren
. You also need to keep track of who you visited,boolean[] visited
.A node is now identified in two ways
"node1","node2",...
nodes
.Oho. Now, you must be sure, that every String representation has exactly one index in the nodes array. (There must be a one-to-one mapping of the two identifications.)
See the problem? There is one
'node'
with three indices, or there are three nodes with the same name!Maybe that is not the same 'node', do you mean the String 'node', or the index 'node'?
To fix this make one identification, one representation, for a node:
No String, or index needed! Just let node be a Node.