【问题标题】:Recursion with yield return elements order in tree递归与树中的收益返回元素顺序
【发布时间】:2012-02-25 22:54:10
【问题描述】:

我有一个递归函数,它返回所有子树节点,给定起始根节点。

private IEnumerable<Node> getAllNodesRecursively(Node subnode)
{
    foreach (Node node in subnode.Nodes)
        getAllNodesRecursively(node);

    yield return subnode;
}

对于以下树结构:

A
|
+--B
|
+--C
|  |
|  +--D
|
+--E

当我尝试这样迭代时:

foreach (Node n in getAllNodesRecursively(a))
{
    Console.WriteLine(n);
}

函数返回唯一的 A 值。

我希望使用带有递归的 yield-return 并检索 Preorder 中的元素(本例中为 A、B、C、D、E)。

(如果我把收益回报放在 foreach 之前,foreach 永远不会发生)。

这可能吗?

【问题讨论】:

  • 如果你把yield return放在前面,你有没有试过不调用foreach?我猜它会被调用。
  • 是的,你是对的。收益返回不会跳过其余代码。似乎它只是允许返回值并保持函数运行的语法糖。我的错。

标签: c# recursion tree yield-return postorder


【解决方案1】:

是的,可以,只需将yield return 放在foreach 之前。您正在考虑普通return 语句的行为。

【讨论】:

  • 我已经修改了我的帖子,因为我的显示内容有误。仅返回第一个元素。如果我将收益回报放在 foreach 之前,也会发生同样的事情。怎么会?
  • 嗯。我现在无法亲自尝试。您是否尝试过使用调试器单步执行代码?
  • 调试器只是跳过递归调用。这很有趣。
【解决方案2】:

您是否尝试过类似的方法:

private IEnumerable<Node> getAllNodesRecursively(Node subnode) 
{ 
    // Return the parent before its children
    yield return subnode; 

    foreach (Node node in subnode.Nodes) 
    {
        foreach(Node n in getAllNodesRecursively(node))
        {
            yield return n;
        }
    }
} 

您的实现正在递归调用getAllNodesRecursively,但忽略了它的返回值。

【讨论】:

  • 这行得通,但为什么我必须再次迭代(内部 foreach)?为什么迭代器方法不允许递归?我已经尝试过调试器,它只是跳过了我的递归调用,除非它在迭代中使用(例如 foreach)。这是为什么呢?
  • @ChristianHayter “除了顶部节点之外的所有节点不会返回两次吗?”没有。
  • Joe 的例子可以稍微简化一下: private IEnumerable getAllNodesRecursively(Node root) { yield return root; foreach (var child in root.Nodes.SelectMany(getAllNodesRecursively)) { yield return child; } }
【解决方案3】:

需要显式迭代+yield返回每个节点ala的子节点:

        public IEnumerable<int> preOrder(Node root)
        {
            if (root == null)
                yield break;

            yield return root.val;

            if (root.left != null)
                foreach (int i in preOrder(root.left))
                    yield return i;

            if (root.right != null)
                foreach (int i in preOrder(root.right))
                    yield return i;
        }

【讨论】:

  • 虽然这段代码 sn-p 可以解决问题,including an explanation 确实有助于提高您的帖子质量。请记住,您是在为将来的读者回答问题,而这些人可能不知道您提出代码建议的原因。
猜你喜欢
  • 1970-01-01
  • 2020-10-05
  • 1970-01-01
  • 2011-05-14
  • 2013-09-28
  • 1970-01-01
  • 1970-01-01
  • 2016-09-27
  • 2016-01-25
相关资源
最近更新 更多