6.6) Recursividad.
     

     En matemáticas se da el nombre de recursión a la técnica consistente en definir una función en términos de sí misma. Puesto que en C una función puede llamar a otras funciones, se permite que una función también pueda llamarse a sí misma.
     

     Toda función definida recursivamente debe contener al menos una definición explícita para alguno de sus argumentos. De no ser así la función puede caer en un bucle infinito.
     
     

    Definición: Se llama recursividad a un proceso mediante el que una función se llama a sí misma de forma repetida, hasta que se satisface alguna determinada condición. El proceso se utiliza para computaciones repetidas en las que cada acción se determina mediante un resultado anterior. Se pueden escribir de esta forma muchos problemas iterativos.


     
     
     

    Se deben satisfacer dos condiciones para que se pueda resolver un problema recursivamente:

     
     
    Primera: El problema se debe escribir en forma recursiva.
       
       
    Segunda: La sentencia del problema debe incluir una condición de fin.
       


     Mostramos a continuación un ejemplo típico de recursividad, hallar el factorial de un número. En forma de traza con las sucesivas llamadas simuladas con ventanas.

       
         
         
         

     
     

 


     
     
     
     

     Ejemplo 1: Posteriormente se muestra nuevamente el problema de la resolución del factorial, pero pidiendo el valor que deseamos hallar por teclado.
     

         
      #include <stdio.h>

      main()
      {
      int n;
      long int factorial (int n);

      printf("Introducir la cantidad entera a la que le queremos hallar el factorial: ");
      scanf("%d", &n);

      printf("%d! = %d\n", n, factorial(n));
      }

      long int factorial (int n)   /* Calcular el factorial */
      {

        if (n <= 1)
          return(1);
        else
          return(n * factorial (n-1));
      }
     
     
    NOTA: Al probar en el compilador de C este ejemplo, es posible que para valores de n que se les introduzcan mayores de 7 (sobrepasando su factorial el valor 32767, que es el Rango tope de los números enteros), nos comience a dar valores de salida incorrectos.
     

     Cuando ejecutamos un programa recursivo, las llamadas recursivas no se ejecutan inmediatamente. Lo que se hace es colocarlas en una pila hasta que la condición de término se encuentra. Entonces se ejecutan las llamadas a la función en orden inverso a como se generaron, como si se fueran sacando de la pila, por tanto el orden sería algo así:

     
     
    1º
    n! = n* (n-1)!
    2º
    (n-1)! = (n-1) * (n-2)!
    3º
    (n-2)! = (n-2) * (n-3)!
    ........
    ...............
    último
    2! = 2 * 1!

 
 
     Los valores reales se devolverán en orden inverso, es decir:
     
     
    1º
    1!=1
    2º
    2! = 2 * 1! = 2 * 1 = 2
    3º
    3! = 3 * 2! = 3 * 2 = 6
    ........
    ...............
    último
    n! = n * (n-1)!= ....
     
     

     El orden inverso de ejecución es una característica típica de todas las funciones recursivas. Si una función recursiva tiene variables locales, se creará un conjunto diferente de variables locales durante cada nueva llamada. Los nombres de las variables locales serán los mismos, como los hallamos declarado en la función. Sin embargo, las variables representarán un conjunto diferente de valores cada vez que se ejecute la función. Cada conjunto de valores se almacenará en la pila, así cuando el proceso recursivo se deshaga (cuando las llamadas a la función se saquen de la pila y sigan su ejecución) podremos disponer de ellas.
     
     
     
     

     En cada llamada de recursiva el compilador utiliza una nueva zona de la pila para almacenar las variables. Esto hace que la administración de la pila enlentezca la ejecución de la función y pueda dar problemas por agotamiento de la memoria de la pila. Por tanto, como toda función recursiva se puede calcular de forma iterativa, es aconsejable utilizar este último modo cuando sea fácil de encontrar.
     
     
     
     

    Ejemplo 2: Mostramos a continuación la versión no recursiva del factorial.
     
     
      int factiterativo (int n) {
         
      int t, res;
        res=1;
        for (t=1; t<= n; t++)
          res*=t;
        return(res);
      }
     
     La versión no recursiva factiterativo() debe estar clara. Utiliza un bucle que empieza en 1 y termina en n y que progresivamente multiplica cada número por el producto móvil.