如何解决图 DFS 方法调用堆栈展开混乱
损坏的方法:hasPathDFSbroken
工作版本:hasPathDFS
我试图理解为什么在损坏的版本中,当调用堆栈开始在 LIM 作为 currNode 展开并且它作为 currentNode 返回到 MEX 时,为什么它不恢复 MEX 邻居上未完成的 for 循环?
任何帮助将不胜感激。谢谢!
const airports = "PHX BKK OKC JFK LAX MEX EZE HEL LOS LAP LIM".split(" ");
const routes = [
["PHX","LAX"],["PHX","JFK"],["JFK","OKC"],"HEL"],"LOS"],["MEX","BKK"],"LIM"],"EZE"],["LIM",];
class Node {
constructor(data) {
this.data = data;
this.neighbors = new Map();
}
addNeighbor(node) {
this.neighbors.set(node.data,node);
return this.neighbors.size;
}
getNeighbors() {
return this.neighbors;
}
}
class Graph {
constructor(edgeDirection = Graph.UNDIRECTED) {
this.nodes = new Map();
this.edgeDirection = edgeDirection;
}
/* ???
When the call stack starts unwinding at LIM as currNode and it gets back to MEX
as currNode,why doesn't the unfinished for loop resume over MEX's neighbors?
*/
hasPathDFSbroken(
start,destination,currNode = this.nodes.get(start),visited = new Map()
) {
if (!currNode) {
return false;
}
visited.set(currNode.data,1);
console.log(
"currNode:",currNode.data,"| neighbors:",[...currNode.getNeighbors().keys()],"| visited:",[...visited.keys()]
);
for (const [neighborData,neighborNode] of currNode
.getNeighbors()
.entries()) {
console.log("currNeighbor:",neighborData);
if (neighborData === destination) {
return true;
}
if (!visited.has(neighborData)) {
return this.hasPathDFSbroken(start,neighborNode,visited);
}
}
return false;
}
// Works but uses contrived found param for pass by ref.
hasPathDFS(
start,visited = new Map(),found = { res: false }
) {
if (!currNode) {
return false;
}
visited.set(currNode.data,neighborData);
if (neighborData === destination) {
return (found.res = true);
}
if (!visited.has(neighborData)) {
this.hasPathDFS(start,visited,found);
}
}
return found.res;
}
addVertex(data) {
if (this.nodes.has(data)) {
return this.nodes.get(data);
}
const vertex = new Node(data);
this.nodes.set(data,vertex);
return vertex;
}
addEdge(source,destination) {
const sourceNode = this.addVertex(source);
const destinationNode = this.addVertex(destination);
sourceNode.addNeighbor(destinationNode);
if (this.edgeDirection === Graph.UNDIRECTED) {
destinationNode.addNeighbor(sourceNode);
}
return [sourceNode,destinationNode];
}
addEdges(edges) {
edges.forEach(([source,destination]) => this.addEdge(source,destination));
return this;
}
print() {
let str = [...this.nodes.values()]
.map(
(node) =>
`${node.data} => ${[...node.getNeighbors().keys()].join(",")}`
)
.join("\n");
str = `${"_".repeat(100)}\n${str}\n${"_".repeat(100)}`;
console.log(str);
return str;
}
}
Graph.UNDIRECTED = Symbol("directed graph"); // two-way edges
Graph.DIRECTED = Symbol("undirected graph"); // one-way edges
const flightPaths = new Graph().addEdges(routes);
flightPaths.print();
console.log(flightPaths.hasPathDFSbroken("HEL","EZE"));
// console.log(flightPaths.hasPathDFS("HEL","EZE")); // working ver.
解决方法
为什么未完成的 for 循环不会在 MEX 的邻居上恢复?
因为您在循环中的 return
语句会立即中断循环和函数。
相反,如果递归调用没有找到目的地,您需要查看返回值并继续循环:
hasPathDFS(start,destination,currNode = this.nodes.get(start),visited = new Map()) {
if (!currNode) {
return false;
}
visited.set(currNode.data,1);
for (const [neighborData,neighborNode] of currNode.getNeighbors()) {
if (neighborData === destination) {
return true;
}
if (!visited.has(neighborData)) {
const found = this.hasPathDFSBroken(start,neighborNode,visited);
if (found) return true;
// ^^^^^^^^^^^^^^^^^^^^^^
// else continue
}
}
return false;
}
如果您尝试构建一个返回路径的 DFS,而不只是返回目标是否可达的布尔值,则该模式应该变得更加明显。
顺便说一句,我建议对 Set
使用 visited
,而不是在循环内部检查 neighborData === destination
,而是在循环外部进行基本情况比较 curreNode.data === destination
循环(实际上,这是一个错误,您的版本不适用于搜索从节点到自身的路径)。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。