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.
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 */
{
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í:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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.