当我在无向图上使用深度优先搜索来确定node1是否可以访问node2时,我遇到了java.lang.OutOfMemoryError。代码如下所示。 (打算删除一些不相关的细节。)
//definition of nodes and edges
Set<Node> nodes = new HashSet<Node>();
Map<Node, Set<Node>> edges = new HashMap<Node, Set<Node>>();
//method to determine if node1 is reachable to node2
public boolean isReachable(int p1, MethodNode m1, ClassNode c1, int p2, MethodNode m2, ClassNode c2) {
Node node1 = new Node (p1,m1,c1);
Node node2 = new Node (p2,m2,c2);
Stack<Node> stack = new Stack<Node>();
stack.push(node1);
while(!stack.isEmpty()){
Node current = null;
current = stack.pop();
//test current node, if its child nodes contains node2, return true
//otherwise, push its child nodes into stack
for(final Node temp : edges.get(current)){
if(temp.equals(node2)){
return true;
}
else{
stack.push(temp);
}
}
}
return false;
}
我猜必须有一些内存耗尽的无限调用,但我无法找到它。
答案 0 :(得分:4)
看起来你的代码很容易追逐它自己的尾巴:如果一个图形包含一个循环,你的代码将耗尽堆栈,因为在将它推入堆栈之前它不会检查顶点是否已经被探索过。
Basic DFS要求您维护一组探索顶点,并仅在未探测到顶点的情况下探索顶点。将此集添加到程序中应解决内存不足问题。
答案 1 :(得分:2)
这是问题
for (final Node temp : edges.get(current)){
if(temp.equals(node2)){
return true;
} else {
stack.push(temp);
}
}
这将推送堆栈中的所有邻居,然后取出其中一个邻居,将其所有邻居推送到堆栈(包括您开始的邻居),等等无限制地进行。您需要将节点标记为已访问,因此不会发生这种情况。唯一不会出现无限循环的情况是,您要查找的节点与您开始的节点直接相邻,或者路径上的节点是否以正确的顺序放入堆栈中纯粹的机会。
答案 2 :(得分:1)
使用您的算法,如果图形有一个循环,它将继续将循环元素推入堆栈,直到内存不足为止。您需要跟踪已经探索过的节点,并避免将它们推入堆栈。有几种标准算法可以做到这一点(A * 和Dijkstra浮现在脑海中)。有关详细信息,请参阅depth first search上的维基百科文章。
答案 3 :(得分:0)
尝试使用额外的
列表与LT;节点&gt; traversed = new ArrayList&lt;节点&gt;();
在此,您可以将要推送的节点保持在堆栈中。 在将其推入堆栈之前执行1步
if(!traversed.contains(temp)) {
stack.push(temp);
}