2011-07-29 5 views
7

Ok, estoy recién aprendiendo recursividad y estoy confundido en un punto. Este es el códigoAmbigüedad de salida de recursión

public class RecursiveDemo { 
    public static void showRecursion (int num) { 
    System.out.println("Entering method. num = " + num); 
    if (num > 1) { 
     showRecursion(num - 1); 
    } 
    System.out.println("Leaving method. num = " + num); 
    } 

    public static void main(String[] args){ 
    showRecursion(2); 
    } 
} 

La salida que estoy recibiendo es:

Entering method. num = 2 
Entering method. num = 1 
Leaving method. num = 1 
Leaving method. num = 2 

Mi pregunta es ¿Por qué aparece la salida "Leaving method. num = 2". ¿No debería parar en "Leaving method. num = 1" ya que num ya ha alcanzado 1?

+4

Tiene ¿Intentó recorrer su código en el depurador? –

+3

+1 para la etiqueta de la tarea. –

+0

Perdón por preguntar esto, pero no tengo ni idea de cómo usar el depurador. ¿Cómo lo usaré? – armitage

Respuesta

7

Una vez que la invocación original de este método abandona la instrucción if, pasa a System.out.println("Leaving method. num = " + num);. Como invocó el mensaje originalmente con el valor 2, 2 es el valor de num para esta parte del código.

Su código se ejecuta como esto (pseudocódigo):

Start First Call 
    if statement 
     Start Second call 
      Skips if statement 
      Print from Second Call 
     End of Second Call 
    End of if Statement 
    Print From First Call 
End of First Call 

Parece que usted tiene un malentendido fundamental de la recursividad. Cuando llama a su método con (num-1) como argumentos, la llamada padre (la primera llamada, en este caso), conserva el valor num como su argumento, que es 2, en este caso.

+0

Pero si 2 es el valor de num, ¿no debería volver a la instrucción if? – armitage

+0

He actualizado mi respuesta. Avíseme si eso lo aclara o no. –

+1

Oh okie doke. Ahora entiendo. La razón por la que se imprime un 2 es porque, aunque se realiza una segunda llamada, la primera llamada sigue activa, ¿verdad? – armitage

4

main llamará showRecursion(2), que a su vez llamar showRecursion(1) (de modo que se produzcan dos "Introducción" mensajes). En ese momento, la condición fallará, por lo que no se produce más recursión. Así que ahora el programa simplemente comienza a regresar de cada llamada de función por turno, imprimiendo los dos mensajes "Saliendo".

3

Es porque la llamada inicial a showRecursion(2) no ha terminado todavía.

6

Así que vamos a comentar la línea de abajo

//showRecursion(num - 1); 

¿Qué le conseguir? Debe ser

Entering method. num = 2 
Leaving method. num = 2 

Y si descomenta la línea anterior. Deberías obtener el que tenías.

+0

Ok, entiendo lo que dices, pero cuando comenté la línea de arriba recibí el resultado: Método de abandono. num = 1 Método de salida. num = 2. Ahora entiendo por qué obtuve "leaving method num = 1", pero no entiendo por qué obtuve "Método de salida. num = 2" ya que num ya se redujo a 1 – armitage

+0

Eso es porque después de que num se reduzca, lo que significa después llamando a showRecursion (1), el sistema todavía tiene cosas que hacer de acuerdo con su código: System.out.println ("Método de salida. num =" + 2); –

+0

Ok, lo tengo. Gracias. – armitage

3

considerar lo siguiente:

public static void showFirstRecursion (int num) { 
    System.out.println("Entering method. num = " + num); 
    if (num > 1) { 
    showSecondRecursion(num - 1); 
    } 
    System.out.println("Leaving method. num = " + num); 
} 

public static void showSecondRecursion (int num) { 
    System.out.println("Entering method. num = " + num); 
    if (num > 1) { 
    showThirdRecursion(num - 1); 
    } 
    System.out.println("Leaving method. num = " + num); 
} 

// I won't bother showing an implementation for showThirdRecursion, because it won't be called. 

public static void main(String[] args){ 
    showFirstRecursion(2); 
} 

No hay problema aquí, ¿verdad? Esperaría ver el primer método ingresado, el segundo ingresado, (el tercero no se ingresó porque num == 0), el segundo a la izquierda, el primero a la izquierda.

Hay realmente nada especial sobre recursividad. Solo hace una llamada a la función que pasa para llamar a la función de la que forma parte la llamada. Una llamada recursiva se comporta, conceptualmente, en todos los aspectos, como cualquier otra llamada a función. El truco es el diseño de un recursivo algoritmo, es decir, que viene con un motivo por el que desea llamar a la misma función en la que ya se encuentra.

+0

Gracias por la explicación muy detallada. Aclaró la mayoría de mis preguntas sobre recursividad. – armitage

1

Las otras respuestas ya cubren la pregunta específica, pero here es información sobre el uso de un depurador. Este tutorial es para Eclipse, pero prácticamente te dice lo que necesitas saber para cualquier depurador visual.

Los conceptos básicos son bastante sencillos, y bien valdría la pena su tiempo para al menos aprender a recorrer el código. Un depurador es una herramienta invaluable para verificar rápidamente la lógica de su programa, y ​​es mucho más fácil que dispersar las instrucciones de impresión en todas partes.

1

Pruebe "showRecursion (5);".

[Respuesta: Esta es la recursión. Hay más de una copia de la variable "num" en la memoria. "num" es un parámetro; no es un campo, y no es estático.]

0

Entonces, lo que entendí fue con cada llamada a un método, la pila se está poblando, es decir. 2,1 pero cuando i> 1 no coincide devuelve/interrumpe la llamada y se da el control a la línea system.out.println, que imprime el valor comenzando desde la parte superior de la pila, es decir 1,2

+0

Intente leer este http://stackoverflow.com/about, para obtener más información acerca de las preguntas/respuestas aquí en SO. Tu contribución no responde la pregunta. Es más un comentario, que puede agregar una vez que aumente su reputación: http://stackoverflow.com/faq#reputation –