[英]Print path from root to a given node in a tree with multiple children
I am trying to print the path from root to a given node containing value of 2. Each node can have children containing several nodes.我正在尝试打印从根到包含值为 2 的给定节点的路径。每个节点可以有包含多个节点的子节点。 Here is a visual reference
这是一个视觉参考
I have flight data like this:我有这样的航班数据:
const flightsTree = {
departureAirportId: 1,
flights: [
{
departureAirportId: 16,
flights: [
{ departureAirportId: 8 },
{ departureAirportId: 17 },
{ departureAirportId: 2 },
{ departureAirportId: 11 },
{
departureAirportId: 10,
flights: [
{
departureAirportId: 17,
flights: [{ departureAirportId: 99 }, { departureAirportId: 2 }],
},
{ departureAirportId: 2 },
],
},
{ departureAirportId: 2 },
{ departureAirportId: 6 },
{ departureAirportId: 3 },
],
},
],
};
This is the code I wrote so far:这是我到目前为止写的代码:
const hasPath = (data, path, from) => {
if (!data) {
return false;
}
path.push(data.departureAirportId);
if (data.departureAirportId === from) {
return true;
}
if (data.flights) {
data.flights.forEach((pRule) => {
hasPath(pRule, path, from);
return true;
});
} else {
path.pop();
return false;
}
return path;
};
console.log(hasPath(flightsTree, [], 2));
So far I'm getting:到目前为止,我得到:
[1, 16, 2, 10, 17, 2, 2, 2]
It seems like it is able to find the node containing the value but not to print the root path except for the first finding.似乎它能够找到包含该值的节点,但除了第一个发现之外,不能打印根路径。
Thanks a lot for your help.非常感谢你的帮助。
This version first calculates all routes and then filter for those that end with the given location.此版本首先计算所有路线,然后过滤以给定位置结尾的路线。 The second part is trivial.
第二部分很琐碎。 The first is a simple recursion;
第一个是简单的递归; when the route has no flights, we simply return an array consisting of an array holding the departure airport.
当路线没有航班时,我们只需返回一个数组,该数组由一个包含出发机场的数组组成。 When it has flights, we recur on those and to each of the results, we prepend our current departure airport:
当它有航班时,我们会重复这些航班,并且对于每个结果,我们都会在我们当前的出发机场前面添加:
const routes = ({departureAirportId, flights = []}) => flights.length == 0? [[departureAirportId]]: flights.flatMap (routes).map (r => [departureAirportId, ...r]) const endingAt = (loc, flights) => routes (flights).filter (r => r [r.length - 1] == loc) const flightsTree = {departureAirportId: 1, flights: [{departureAirportId: 16, flights: [{departureAirportId: 8}, {departureAirportId: 17}, {departureAirportId: 2}, {departureAirportId: 11}, {departureAirportId: 10, flights: [{departureAirportId: 17, flights: [{departureAirportId: 99}, {departureAirportId: 2}]}, {departureAirportId: 2}]}, {departureAirportId: 2}, {departureAirportId: 6}, {departureAirportId: 3}]}]} console.log (endingAt (2, flightsTree))
.as-console-wrapper {max-height: 100%;important: top: 0}
There are two assumptions here.这里有两个假设。 The first is that you want only those that end at the target airport.
第一个是您只想要那些在目标机场结束的人。 If you want all paths that go through airport 2, you can replace
endingAt
with a function that filters the routes testing if any contain the target.如果您想要go 通过机场 2 的所有路径,您可以将
endingAt
替换为 function 过滤测试路线(如果有的话)包含目标。
The second is that the order of the results is not that important.第二个是结果的顺序不是那么重要。 This depth-first traversal is simpler, but if the order of the results in your image is important, we can certainly write a breadth-first traversal version.
这种深度优先遍历比较简单,但是如果你的图像中结果的顺序很重要,我们当然可以写一个广度优先遍历的版本。
Scott's answer is beautiful.斯科特的回答很漂亮。 I'm going to share an approach using generators because often times problems like these involve only finding one or some known amount of solutions.
我将分享一种使用生成器的方法,因为此类问题通常只涉及找到一个或一些已知数量的解决方案。 Generators allow us to stop computation early instead of computing all routes.
生成器允许我们提前停止计算,而不是计算所有路线。 Notice the similarity between the structure of the generator approach and Scott's program -
请注意生成器方法的结构与 Scott 的程序之间的相似之处 -
function* routes ({departureAirportId, flights = []}, r = []) { if (flights.length === 0) yield [...r, departureAirportId] else for (const q of flights) yield* routes(q, [...r, departureAirportId]) } function* endingAt (t, loc) { for (const r of routes(t)) if(r[r.length - 1] == loc) yield r } const flightsTree = {departureAirportId: 1, flights: [{departureAirportId: 16, flights: [{departureAirportId: 8}, {departureAirportId: 17}, {departureAirportId: 2}, {departureAirportId: 11}, {departureAirportId: 10, flights: [{departureAirportId: 17, flights: [{departureAirportId: 99}, {departureAirportId: 2}]}, {departureAirportId: 2}]}, {departureAirportId: 2}, {departureAirportId: 6}, {departureAirportId: 3}]}]} console.log(Array.from(endingAt(flightsTree, 2)))
The above approach is sound because it decomposes the problem into two separate parts, routes
and endingAt
.上述方法是合理的,因为它将问题分解为两个独立的部分,
routes
和endingAt
。 However the two functions can be collapsed into one, if you wish -但是,如果您愿意,这两个功能可以合并为一个 -
function* endingAt (t, loc, r = []) { if (t.flights) for (const q of t.flights) yield* endingAt(q, loc, [...r, t.departureAirportId]) else if (t.departureAirportId == loc) yield [...r, t.departureAirportId] } const flightsTree = {departureAirportId: 1, flights: [{departureAirportId: 16, flights: [{departureAirportId: 8}, {departureAirportId: 17}, {departureAirportId: 2}, {departureAirportId: 11}, {departureAirportId: 10, flights: [{departureAirportId: 17, flights: [{departureAirportId: 99}, {departureAirportId: 2}]}, {departureAirportId: 2}]}, {departureAirportId: 2}, {departureAirportId: 6}, {departureAirportId: 3}]}]} console.log(Array.from(endingAt(flightsTree, 2)))
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.