2012-02-03 4 views
9

Tengo una función recursiva que devuelve todos los nodos de subárbol, dado el nodo raíz de inicio.Recursión con orden de elementos de retorno de rendimiento en el árbol

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

    yield return subnode; 
} 

Para la siguiente estructura:

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

Cuando trato de repetir como tal:

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

la función devuelve el único el valor A.

Deseo usar yield-return con recursión y recuperar elementos en el Preorder (A, B, C, D, E en este ejemplo).

(Si pongo el rendimiento antes del foreach, el foreach nunca sucedería).

¿Esto es posible?

+0

¿Has intentado que no se llame al foreach si pones el retorno de rendimiento al frente? Supongo que se llamará. – okrumnow

+0

Sí, tenías razón. El rendimiento obtenido no omite el resto del código. Parece que es solo un azúcar sintáctico para permitir el retorno del valor y aún así mantener la función en funcionamiento. Mi error. –

Respuesta

16

Ha intentado algo así como:

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

Su aplicación está llamando getAllNodesRecursively de forma recursiva, pero ignorando su valor de retorno.

+0

Esto funciona, pero ¿por qué tengo que repetir de nuevo (foreach interno)? ¿Por qué el método del iterador no permite la recursión tal como es? Lo intenté con el depurador y simplemente salté mi llamada recursiva a menos que se use en una iteración (como foreach). ¿Porqué es eso? –

+0

@ChristianHayter "¿No devolverá eso todo, excepto el nodo superior dos veces?" No. – Joe

+1

El ejemplo de Joe se puede simplificar un poco: private IEnumerable getAllNodesRecursively (raíz del nodo) { yield return root; foreach (var child en root.Nodes.SelectMany (getAllNodesRecursively)) { rendimiento return child; } } – peter70

3

Sí, es posible, simplemente ponga el yield return antes del foreach. Está pensando en el comportamiento de una declaración normal de return.

+0

Modifiqué mi publicación, porque me equivoqué en lo que se mostrará. Solo se devuelve el primer elemento. Si pongo el retorno de rendimiento antes del foreach, sucede lo mismo. ¿Cómo? –

+0

Hmmm. No estoy en posición de probar esto por mi cuenta ahora mismo. ¿Has intentado recorrer el código con el depurador? –

+0

El depurador simplemente omite la llamada recursiva. Esa es una interesante. –

1
 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; 
     } 
+0

Si bien este fragmento de código puede resolver la pregunta, [incluyendo una explicación] (http://meta.stackexchange.com/questions/114762/explaining-entirely-code-based-answers) realmente ayuda a mejorar la calidad de tu publicación Recuerde que usted está respondiendo la pregunta a los lectores en el futuro, y es posible que esas personas no sepan los motivos de su sugerencia de código. – lokusking

Cuestiones relacionadas