[英]Traversing a nested hierarchy of any depth from bottom - up
像這樣嵌套嵌套的遞歸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
}
]
}
]
}
]
}
]
}
使用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; }
}
到目前為止還不錯...但是現在我需要從層次結構的底部開始向上工作(從FooId = 5處的子級開始),然后再回到根目錄。 我如何有效地解決這個問題?
從您的問題尚不清楚,您是否需要后序(深度優先)遍歷,還是反向級別遍歷(寬度優先,反向)。 假設您想要后期訂購,該算法非常簡單:
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;
}
}
每個節點僅在其所有后代之后才產生,因此這是一個后序遍歷。
如果樹很淺,那是相當有效的,但是您說您希望解決“任何深度”的樹的問題。 這種方法僅對深度達幾十個級別的樹有效,因為它是O(nd),其中n是節點總數,d是平均深度。 平均深度取決於分支因子,因此可能低至1或高至n,這使其成為潛在的四元算法。
此外,由於它使用O(dmax)堆棧空間,其中dmax是最大深度,因此我們可以刪除調用堆棧。
因此:如果您有數百或數千個級別,請使用顯式堆棧技術。
練習 :重寫我的算法以使用顯式堆棧,而不是將調用堆棧用作隱式堆棧。
但是你說你需要任何深度的樹木。 如果樹中有數十億或數萬億個節點,深度達數十億或數萬億怎么辦? 在這種情況下,您將需要使用外部存儲器解決方案,並且我建議構建一個專門用於解決此問題的自定義存儲系統。 對大規模圖形數據庫進行一些研究,可以解決此類問題。
無論如何,既然您已經有了通用的解決方案,那么您的特定解決方案將非常簡單:
var ids = root.Foos
.Postorder(f => f.Foos)
.Select(f => f.FooId)
.ToList();
管他呢。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.