簡體   English   中英

從下到上遍歷任何深度的嵌套層次結構

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM