我试图编写一个路由功能,它将从任意两个给定位置返回所有可能的路线(我称之为"空格"),但是我被卡住了写递归函数。
我的数据看起来像这样:
const allSpaces = [
{
id: 0,
name: 'Living Room',
connectedSpaces: [1,2]
},
{
id: 1,
name: 'Hallway A',
connectedSpaces: [0,4]
},
{
id: 2,
name: 'Hallway B',
connectedSpaces: [0,4]
},
{
id: 3,
name: 'Bedroom',
connectedSpaces: [1,2]
}
];
因此,调用getAllRoutes(0,3)
方法将遍历所有可能的路由并返回一个数组数组:
[
[0,1,3],
[0,2,3]
]
请记住,这可能并不总是像我的示例那样简单化数据集(即,走廊A可能有一个提供替代路线的分支,或者可能与以前访问过的空间重新交叉)。
我很难过。我已经对递归函数进行了多次尝试,但最终会出现不完整的列表或无限循环。任何帮助将不胜感激!
答案 0 :(得分:0)
每当你发现自己遇到这样的问题时,就会想出一种简单的方法来想象发生了什么。为了了解您正在使用的图表,我编写了几行代码来可视化图表。
通过可视化,我注意到数据中可能存在一个小错误。我认为空格1和2应该连接到0
和3
而不是0
和4
。我在数据中对此进行了调整,并添加了额外的测试空间。
如果您愿意,可以通过展开下面的代码段来查看可视化效果。
const allSpaces=[{id:0,name:"Living Room",connectedSpaces:[1,2]},{id:1,name:"Hallway A",connectedSpaces:[0,3,4]},{id:2,name:"Hallway B",connectedSpaces:[0,3]},{id:3,name:"Bedroom",connectedSpaces:[1,2]}, {id:4,name:"Master bedroom",connectedSpaces:[1]}];
const Edge = (() => {
// Do not support two way edges. Cache from and to internally:
const cache = new Map();
const Edge = (from, to) => {
const id = `${Math.min(from, to)}.${Math.max(from, to)}`;
const length = 1;
if (!cache.has(id)) {
cache.set(id, { from, to, id, length });
}
return cache.get(id);
}
return (from => to => Edge(from, to));
})();
const edges = uniques(allSpaces.reduce(
(edges, node) => edges.concat(
node.connectedSpaces.map(Edge(node.id))
), []
));
const Node = ({ id, name }) => ({ id, label: name });
const nodes = allSpaces.map(Node);
const network = new vis.Network(
document.getElementById("cvs"),
{ nodes, edges },
{}
);
function uniques(arr) { return Array.from(new Set(arr).values()); }

<link href="https://cdnjs.cloudflare.com/ajax/libs/vis/4.21.0/vis-network.min.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vis/4.21.0/vis.min.js"></script>
<div id="cvs" style="height: 300px"></div>
&#13;
能够查看我们的数据,可以更轻松地检查我们的功能是否有效!现在,您已经要求找到从A到B的所有路径。请注意,随着您添加更多节点,可能非常快速的路径数量增加。 (例如,查看Traveling Salesman Problem)。
如果你真的在寻找最短的路径,你可能需要调整下面的代码来使用Dijkstra's Shortest Path algorithm,就像SLaks在评论中建议的那样。
但是,由于示例集很小,并且您要求所有路由,请强制它:
或者,在代码中:
const walk = (destination, paths, path, node) => {
// Walking in circles
if (path.includes(node.id)) // <-- expensive, for large paths use a Set
return paths;
// End reached
if (node.id === destination)
return paths.concat([path.concat(node.id)]);
// Take next step recursively
return node.connectedSpaces
.reduce(
(acc, id) => walk(destination, acc, path.concat(node.id), spaceMap.get(id)),
paths
);
}
这是一个正在运行的代码段,您可以使用它来逐步查看会发生什么:
const allSpaces=[{id:0,name:"Living Room",connectedSpaces:[1,2]},{id:1,name:"Hallway A",connectedSpaces:[0,3,4]},{id:2,name:"Hallway B",connectedSpaces:[0,3]},{id:3,name:"Bedroom",connectedSpaces:[1,2]}, {id:4,name:"Master bedroom",connectedSpaces:[1]}];
const spaceMap = new Map(allSpaces.map(s => [s.id, s]));
const walk = (destination, paths, path, node) => {
// Walking in circles
if (path.includes(node.id)) // <-- expensive, for large paths use a Set
return paths;
// End reached
if (node.id === destination)
return paths.concat([path.concat(node.id)]);
// Take next step recursively
return node.connectedSpaces
.reduce(
(acc, id) => walk(destination, acc, path.concat(node.id), spaceMap.get(id)),
paths
);
}
const calcRoute = (from, to) => {
const routes = walk(to, [], [], spaceMap.get(from));
return `
Found ${routes.length} route(s) to ${spaceMap.get(to).name}
${routes.map(r => r.map(id => spaceMap.get(id).name).join(" -> ")).join("\n")}
`;
}
console.log(calcRoute(0, 3));
console.log(calcRoute(0, 4));
&#13;