C# 如何在遍历树结构时匹配路径

C# 如何在遍历树结构时匹配路径,c#,algorithm,tree,traversal,C#,Algorithm,Tree,Traversal,我有一个树状结构,包含父母和孩子。父母可以拥有的子女数量没有限制。树中的每个节点都有一些特定的属性集 我有一个类似列表的结构,它表示一条路径。路径中的每个节点都具有相同的属性集和某些特定值。路径中的第一个节点始终与上述树的根节点相同 我想从根开始遍历树,通过比较树上节点的属性和路径上节点的属性来检查树中是否存在路径。同时保存满足匹配条件的树节点的记录。请注意,TreeNode和PathNode是完全不同的类型,它们只有一些常见的属性,例如名称、Id、位置等 我能想到的最简单的方法是使用递归调用遍

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

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

我想从根开始遍历树,通过比较树上节点的属性和路径上节点的属性来检查树中是否存在路径。同时保存满足匹配条件的树节点的记录。请注意,TreeNode和PathNode是完全不同的类型,它们只有一些常见的属性,例如名称、Id、位置等


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

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

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)));
                }
            }
        }
    }

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

路径为:

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

  • 后跟零棵或多棵树(子树)列表的节点
请注意,在此定义中没有空树。你说过总有根的

我们现在定义一个谓词“match”,如下所示

  • 路径片段可能与树节点匹配。如何匹配取决于你
  • 空路径匹配所有树
  • 假设我们有一个头部后面跟着一个尾巴,一个节点后面跟着子节点。当且仅当(1)头部与节点匹配,以及(2)尾部为空,或者至少存在一个子级与尾部匹配时,路径才与树匹配
这个草图应该足够详细,可以用您选择的语言编写一个实现

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