【问题标题】:Recursively traversing a tree in C# from top down by row从上到下逐行递归遍历C#中的树
【发布时间】:2010-08-19 03:28:10
【问题描述】:

最近一个朋友提出的一个有趣的问题:假设你有一个树中所有节点的 List。您将如何从根节点逐行遍历树,以便找到具有特定值的第一个节点。假设每个节点都有 3 个属性:它的名称/位置、其父节点的身份以及谁“拥有”该节点。问题是你想在树中找到你“拥有”的最高节点,不管它在哪个分支上。我非常了解基本逻辑,以找到第一组子节点,您要查找所有节点,其中父集作为第一个节点。但是,您将如何递归搜索节点列表 以找到您拥有的最高节点?

【问题讨论】:

  • 请输入代码。至少定义你正在使用的结构......
  • 没有代码,只是我们随机讨论的一个逻辑难题。但它是一组对象的列表。例如,这些对象可以有自己的 Guid、对其父对象的 Guid 引用以及任何像“apple”这样的任意值。在这种情况下,您需要找到值为“apple”的“最高”元素。有意义吗?

标签: c# recursion tree


【解决方案1】:

您正在寻找广度优先搜索。它通常使用队列来实现:

public Node FindFirstByBreadthFirst(this Node node, Predicate<Node> match)
{
    var queue = new Queue<Node>();
    queue.Enqueue(tree.RootNode);

    while (queue.Count > 0)
    {
        // Take the next node from the front of the queue
        var node = queue.Dequeue();

        // Process the node 'node'
        if (match(node))
            return node;

        // Add the node’s children to the back of the queue
        foreach (var child in node.Children)
            queue.Enqueue(child);
    }

    // None of the nodes matched the specified predicate.
    return null;
}

【讨论】:

  • 啊,是的。哇,我的老算法教授现在可能会结束我。谢谢!
【解决方案2】:

算法:

Put the root node in a queue.

Repeat
    Take item from queue;
    Matching?  return Item
    Add all children to the queue
Until Queue is empty

【讨论】:

    【解决方案3】:

    更新:哈哈,哇,这完全错了,我刚刚意识到(因为它没有按照你的要求做)。没关系——看起来你已经得到了正确的答案,反正:)


    我想我理解你的问题。如果我有什么问题,请告诉我。

    你有一个看起来像这样的NodeType 类:

    class NodeType
    {
        public string Name { get; }
        public NodeType Parent { get; }
        public int OwnderId { get; }
    }
    

    首要任务是编写一个接受NodeType 参数的函数,并在给定NodeType 对象的一些可枚举集合的情况下,以递归方式返回其所有后代:

    IEnumerable<NodeType> GetNodeChildren(NodeType node, IEnumerable<NodeType> nodes)
    {
        var children = nodes.Where(n => n.Parent == node);
    
        if (children.Any())
        {
            foreach (NodeType child in children)
            {
                yield return child;
    
                var grandchildren = GetNodeChildren(child);
                foreach (NodeType grandchild in grandchildren)
                {
                    yield return grandchild;
                }
            }
        }
    }
    

    接下来:编写一个函数,该函数接受 NodeType 对象并找到具有指定 OwnerId 的最高后代。这确实是一个非常简单的操作,所以我什至不会定义一个合适的函数;我将只使用一个 lambda:

    Func<NodeType, int, NodeType> findHighestDescendent = (node, id) => {
        return GetNodeChildren(node).FirstOrDefault(child => child.OwnerId == id);
    };
    

    现在对于任何给定的 Id 值,找到最高匹配的 NodeType 是非常简单的:

    int id = 10; // just for example
    
    NodeType highestOwnedNode = nodes
        .Select(n => findHighestDescendent(n, id))
        .FirstOrDefault(n => (n != null));
    

    【讨论】:

    • 作为注释...我认为您需要将递归调用更改为:var grandchildren = GetNodeChildren(child, nodes);
    【解决方案4】:
    public static Control FindChildControlByDepth(this Control Page, string ControlID, int depth)
            {
                if (depth > 10)
                    throw new ArgumentException("Cannot search beyond a depth of 10", "depth"); 
                foreach (Control c in Page.Controls)
                {
                    if (c.ID == ControlID)
                        return c;
                    if (depth > 0)
                    {
                        foreach (Control c1 in c.Controls)
                        {
                            if (c1.ID == ControlID)
                                return c1;
                            if (depth > 1)
                            {
                                foreach (Control c2 in c1.Controls)
                                {
                                    if (c2.ID == ControlID)
                                        return c2;
                                    if (depth > 2)
                                    {
                                        foreach (Control c3 in c2.Controls)
                                        {
                                            if (c3.ID == ControlID)
                                                return c3;
                                            if (depth > 3)
                                            {
                                                foreach (Control c4 in c3.Controls)
                                                {
                                                    if (c4.ID == ControlID)
                                                        return c4;
                                                    if (depth > 4)
                                                    {
                                                        foreach (Control c5 in c4.Controls)
                                                        {
                                                            if (c5.ID == ControlID)
                                                                return c5;
                                                            if (depth > 5)
                                                            {
                                                                foreach (Control c6 in c5.Controls)
                                                                {
                                                                    if (c6.ID == ControlID)
                                                                        return c6;
                                                                    if (depth > 6)
                                                                    {
                                                                        foreach (Control c7 in c6.Controls)
                                                                        {
                                                                            if (c7.ID == ControlID)
                                                                                return c7;
                                                                            if (depth > 8)
                                                                            {
                                                                                foreach (Control c8 in c7.Controls)
                                                                                {
                                                                                    if (c8.ID == ControlID)
                                                                                        return c8;
                                                                                    if (depth > 9)
                                                                                    {
                                                                                        foreach (Control c9 in c8.Controls)
                                                                                        {
                                                                                            if (c9.ID == ControlID)
                                                                                                return c9;
                                                                                        }
                                                                                    }
                                                                                }
                                                                            }
                                                                        }
                                                                    }
                                                                }
                                                            }
                                                        }
    
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
    
                    }
                }
                return null;
            }
    

    【讨论】:

    • 请您解释一下这是如何解决最初提出的问题的?
    • 这是什么鬼?
    • 在成为 Stackoverflow 用户 5 年后,这是第一个让我大笑的答案。你是我的好伙伴,你是独一无二的!
    • 我投票赞成,因为 OMG LOL
    猜你喜欢
    • 2018-07-12
    • 2014-03-11
    • 1970-01-01
    • 1970-01-01
    • 2017-05-11
    • 2016-08-24
    • 2021-05-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多