【问题标题】:How to match a path while traversing a tree structure如何在遍历树结构时匹配路径
【发布时间】:2014-12-12 14:18:28
【问题描述】:

我有一个包含父母和孩子的树状结构。父母可以拥有的孩子数量没有限制。树中的每个节点都有一些特定的属性集。

我有一个类似结构的列表,它代表一条路径。路径中的每个节点都具有相同的一组属性和一些特定的值。路径中的第一个节点始终与上述树的根相同。

我想从 Root 开始遍历 Tree,通过比较 Node on Tree 的属性和 Node on path 的属性来检查路径是否存在于树中。同时保存满足匹配条件的TreeNodes的记录。请注意,TreeNode 和 PathNode 是完全不同的类型,它们只是具有一些共同的属性,例如姓名、身份证、位置等。

我能想到的最简单的方法是递归调用来遍历树的子节点,并且对于树的每一级我比较路径中的下一个节点,但我不确定是否有任何简单的方法它。我将不得不在 C# 中实现它,所以是否有任何特定的结构或库可以做到这一点。任何特定于语言的解决方案都会非常有帮助,否则我可以将其翻译成 C#,只需要了解它应该如何设计。

【问题讨论】:

    标签: c# algorithm tree traversal


    【解决方案1】:

    让我们抽象地解决这个问题。

    路径是:

    • 空路径,或
    • 路径片段(路径的头部)后跟路径(路径的尾部)

    一棵树是:

    • 一个节点,后跟零个或多个树(子节点)的列表。

    请注意,在此定义中没有空树。你说总有根。

    我们现在定义一个谓词“匹配”如下。

    • 路径片段可能与树节点匹配。如何匹配由您决定。
    • 空路径匹配所有树。
    • 假设我们有一个头后跟一个尾,一个节点后跟子节点。当且仅当 (1) 头部与节点匹配,并且 (2) 尾部为空或至少存在一个与尾部匹配的子节点时,路径才与树匹配。

    这个草图应该足够详细,可以用您选择的语言编写实现。

    【讨论】:

      【解决方案2】:

      我写了下面的扩展来遍历递归目录/文件树。这可能不是您的确切情况,但听起来很相似。我希望代码有所帮助。

      public static IEnumerable<Tuple<TValue, string>> TraverseValuesWithPaths<T, TValue>(this IEnumerable<T> items,
          Func<T, IEnumerable<T>> childSelector, Func<T, IEnumerable<TValue>> valueSelector, Func<T, string> childNameSelector, Func<TValue, string> valueNameSelector, string pathStart = null, string separator = null)
          {
              Func<string, string, string> pathCombine = (a, b) => string.Concat(a, separator, b);
      
              var stack = new Stack<Tuple<T, string>>(items.Select(i => new Tuple<T, string>(i, pathCombine(pathStart, childNameSelector(i)))));
      
              while (stack.Any())
              {
                  var next = stack.Pop();
      
                  foreach (var child in childSelector(next.Item1))
                  {
                      stack.Push(new Tuple<T, string>(child, pathCombine(next.Item2, childNameSelector(child))));
                  }
      
                  var values = valueSelector(next.Item1);
      
                  if (values != null)
                  {
                      foreach (var value in values)
                      {
                          yield return new Tuple<TValue, string>(value, pathCombine(next.Item2, valueNameSelector(value)));
                      }
                  }
              }
          }
      

      用法

      // produce flat list of files and path 
      var allFiles = folders.TraverseValuesWithPaths(folder => folder.Folders, folder => folder.Files, folder => folder.Name, file => file.Name, "\"", "\"");
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2023-03-11
        • 1970-01-01
        • 2018-12-27
        • 1970-01-01
        • 1970-01-01
        • 2016-10-22
        • 1970-01-01
        相关资源
        最近更新 更多