使用c#lambdas进行递归非二进制,非排序树搜索

时间:2009-07-23 22:28:43

标签: c# recursion lambda tree

class TreeNode
{
    public string Value { get; set;}
    public Collection<TreeNode> Nodes { get; set;}


    public TreeNode()
    {
        Nodes = new Collection<TreeNode>();
    }
}

1)如何编写递归lambda表达式以返回具有特定值的TreeNode(如果未找到则返回null),假设值是唯一的?当然#1可以使用#2来回答,但我想如果你知道没有重复,可能会有一种更有效的方法。

2)假设值不是唯一的,现在返回匹配列表?

2 个答案:

答案 0 :(得分:6)

编辑:更正了代码,我确实编译并测试了两段代码,但在修复VS之前我必须先粘贴版本。对不起。

我添加了一个带有代码的Subversion存储库,包括单元测试,以确保它现在按预期工作,是here,使用用户名和密码登录为“guest”,没有报价。


像这样:

1 :先找

Func<TreeNode, String, TreeNode> findNode = null; // satisfy recursion re-use
findNode = (n, value) =>
{
    if (n == null) return n;
    if (n.Value == value) return n;
    foreach (var subNode in n.Nodes)
    {
        TreeNode foundNode = findNode(subNode, value);
        if (foundNode != null) return foundNode;
    }
    return null;
};

请注意,此处的陷阱是对于要递归的lambda或委托,在将实际委托分配给变量之前,需要先使用已知值声明变量。否则,编译器会在给定值之前抱怨您正在使用变量。

2 :全部找到

Func<TreeNode, String, List<TreeNode>> findNodes = null;
findNodes = (n, value) =>
{
    var result = new List<TreeNode>();
    if (n == null) return result;
    if (n.Value == value) result.Add(n);
    foreach (var subNode in n.Nodes)
    {
        result.AddRange(findNodes(subNode, value));
    }
    return result;
};

这里的诀窍就是收集每个级别的节点,并向上聚合。

答案 1 :(得分:0)

这个怎么样..

public class Node<T> where T:IComparable
{
    public T Value { get; set; }

    public IList<Node<T>> Children { get; set; }

    public override string ToString()
    {
        return Value.ToString();
    }

    public static Func<T, Node<T>, Node<T>> GetFindFirstFunc()
    {
        Func<T, Node<T>,Node<T>> func = null;
        func = (value,currentNode) =>
            {
                if (currentNode.Value.CompareTo(value) == 0)
                {
                    return currentNode;
                }
                if (currentNode.Children != null)
                {
                    foreach (var child in currentNode.Children)
                    {                            
                        var result = func(value, child);
                        if (result != null)
                        {
                            //found the first match, pass that out as the return value as the call stack unwinds
                            return result;
                        }
                    }
                }
                return null;
            };
        return func;
    }

    public static Func<T, Node<T>, IEnumerable<Node<T>>> GetFindAllFunc()
    {
        Func<T, Node<T>, IEnumerable<Node<T>>> func = null;
        List<Node<T>> matches = new List<Node<T>>();
        func = (value, currentNode) =>
        {
            //capture the matches  List<Node<T>> in a closure so that we don't re-create it recursively every time.
            if (currentNode.Value.CompareTo(value) == 0)
            {
                matches.Add(currentNode);
            }
            if (currentNode.Children != null)
            {
                //process all nodes
                foreach (var child in currentNode.Children)
                {
                    func(value, child);
                }
            }
            return matches;
        };
        return func;
    }       
}

这是调用代码:

static void Main(string[] args)
    {
        Node<int> rootNode = new Node<int>
        {
            Value = 1,
            Children = new List<Node<int>>
             {
                 new Node<int>
                 {  Value = 2,
                                 Children = new List<Node<int>>
                                 {
                                     new Node<int>{ Value = 7},
                                     new Node<int>{ Value = 4}                                                            
                                 }
                 },
                 new Node<int>
                 {  Value = 5,
                                 Children = new List<Node<int>>
                                 {
                                     new Node<int>{ Value = 6},
                                     new Node<int>{ Value = 7}                                                            
                                 }
                 }
             }
        };


        Func<int, Node<int>, Node<int>> findFirst = Node<int>.GetFindFirstFunc();
        var firstValue = findFirst(7, rootNode);           



        Func<int, Node<int>, IEnumerable<Node<int>>> findAll = Node<int>.GetFindAllFunc();
        var allvalues = findAll(7, rootNode);           
    }