[英]Traversing a nested hierarchy of any depth from bottom - up
Take a nested recursive JSON snippet like this that can go on to any depth: 像这样嵌套嵌套的递归JSON代码片段,可以继续进行到任何深度:
{
"Id": null,
"Foos": [
{
"FooId": 1,
"FooName": "ABC",
"Foos": [
{
"FooId": 2,
"FooName": "DEF",
"Foos": null
},
{
"FooId": 3,
"FooName": "GHI",
"Foos": [
{
"FooId": 4,
"FooName": "JKL",
"Foos": null
},
{
"FooId": 5,
"FooName": "MNO",
"Foos": [
{
"FooId": 6,
"FooName": "PQR",
"Foos": null
},
{
"FooId": 7,
"FooName": "STU",
"Foos": null
}
]
}
]
}
]
}
]
}
Using JSON.NET I can map that into a structure like this: 使用JSON.NET,我可以将其映射到这样的结构中:
public class Root {
public string Id { get; set; }
public List<Foo> Foos { get; set; }
}
public class Foo {
public int FooId { get; set; }
public string FooName { get; set; }
public List<Foo> Foos { get; set; }
}
so far so good...but now I need to work from the bottom of the hierarchy upward (starting with the children at FooId=5) and then working my way back up to the root. 到目前为止还不错...但是现在我需要从层次结构的底部开始向上工作(从FooId = 5处的子级开始),然后再回到根目录。 How do I tackle this efficiently?
我如何有效地解决这个问题?
It's unclear from your question whether you want a postorder (depth-first) traversal, or a reverse level traversal (breadth-first, reversed). 从您的问题尚不清楚,您是否需要后序(深度优先)遍历,还是反向级别遍历(宽度优先,反向)。 Assuming you want postorder, the algorithm is straightforward:
假设您想要后期订购,该算法非常简单:
public static IEnumerable<T> Postorder<T>(
this IEnumerable<T> nodes,
Func<T, IEnumerable<T>> children)
{
foreach(T node in nodes)
{
foreach(T descendant in children(node).Postorder(children))
yield return descendant;
yield return node;
}
}
Every node is yielded only after all of its descendants, so this is a postorder traversal. 每个节点仅在其所有后代之后才产生,因此这是一个后序遍历。
That's reasonably efficient if the tree is shallow, but you say you wish to solve the problem for a tree of "any depth". 如果树很浅,那是相当有效的,但是您说您希望解决“任何深度”的树的问题。 This approach will only work efficiently for trees of depths up to a few dozen levels because it is O(nd) where n is the total number of nodes and d is the average depth;
这种方法仅对深度达几十个级别的树有效,因为它是O(nd),其中n是节点总数,d是平均深度。 the average depth depends on the branching factor, and so could be as low as 1 or as high as n, making this a potentially quadradic algorithm.
平均深度取决于分支因子,因此可能低至1或高至n,这使其成为潜在的四元算法。
Moreover, since it uses O(dmax) stack space where dmax is the maximum depth, we can blow the call stack. 此外,由于它使用O(dmax)堆栈空间,其中dmax是最大深度,因此我们可以删除调用堆栈。
Thus: if you have hundreds or thousands of levels, use the explicit stack technique. 因此:如果您有数百或数千个级别,请使用显式堆栈技术。
Exercise : Rewrite my algorithm to use an explicit stack rather than using the call stack as an implicit stack. 练习 :重写我的算法以使用显式堆栈,而不是将调用堆栈用作隐式堆栈。
But you said you need trees of any depth . 但是你说你需要任何深度的树木。 What if there are billions, or trillions of nodes in the tree, billions or trillions deep?
如果树中有数十亿或数万亿个节点,深度达数十亿或数万亿怎么办? In that case you'll need to go with an external memory solution, and I would recommend building a custom storage system dedicated to this problem;
在这种情况下,您将需要使用外部存储器解决方案,并且我建议构建一个专门用于解决此问题的自定义存储系统。 do some research on at-scale graph databases, which can solve this sort of problem.
对大规模图形数据库进行一些研究,可以解决此类问题。
Anyways, now that you have the general solution, your specific solution is straightforward: 无论如何,既然您已经有了通用的解决方案,那么您的特定解决方案将非常简单:
var ids = root.Foos
.Postorder(f => f.Foos)
.Select(f => f.FooId)
.ToList();
or whatever. 管他呢。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.