微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如何在C#中折叠n-ary树

我想对n-ary Tree数据结构进行折叠. (fold在 Linq中也称为Aggregate)
我设法找到了一个有效的解决方案:

public static R Aggregate<T,R>(T node,Func<T,IEnumerable<T>> getChildren,IEnumerable<R>,R> aggregator)
{
    var childResults = getChildren(node)
                      .Select(c => Aggregate(c,getChildren,aggregator));

    return aggregator(node,childResults);
}

getChildren是一个定义如何获取给定节点的子节点的函数.它必须为叶节点返回一个空的IEnumerable.
聚合器定义如何使用当前节点及其子节点的结果处理节点.

解决方案似乎有效,但有一些问题:

>算法是递归的,它将为深树打击堆栈.
如何重写函数以防止堆栈溢出?
>算法是懒惰的,但只是一种.
例如如果聚合器仅使用子节点的Enumerable.First结果,则仅遍历树的最左侧分支.然而,使用Enumerable.Last遍历整个树,即使计算只需要最右边的分支.
如何让算法真正变得懒惰?

F#解决方案欢迎,但C#首选.

解决方法

您可以使用显式堆栈遍历树,而不是递归,以避免消耗堆栈空间:

public static IEnumerable<T> Traverse<T>(
    this IEnumerable<T> source,IEnumerable<T>> childrenSelector)
{
    var stack = new Stack<T>(source);
    while (stack.Any())
    {
        var next = stack.Pop();
        yield return next;
        foreach (var child in childrenSelector(next))
            stack.Push(child);
    }
}

如果你想然后“向后”遍历,你可以在调用它时简单地调整子选择器,而不是调用Last而不是First:

Traverse(root,node => nodes.Reverse());

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。

相关推荐