Concepto de recursión Recursión (recursividad, recurrencia) Definición recursiva: En la definición aparece lo que se define Factorial(N) = N x Factorial(N-1) (N >= 0)
Definiciones recursivas Factorial(N) = N x Factorial(N-1) El factorial se define en función de sí mismo Los programas no pueden manejar la recursión infinita La definición recursiva debe adjuntar uno o más casos base Caso base: aquel en el que no se utiliza la definición recursiva Proporcionan puntos finales de cálculo:
El valor de N se va aproximando al valor del caso base (0) N x Factorial(N-1) si N > 0 Caso recursivo (inducción) Factorial(N) 1 si N = 0 Caso base (o de parada)
Algoritmos recursivos Funciones recursivas Una función puede implementar un algoritmo recursivo La función se llamará a sí misma si no se ha llegado al caso base
long long int factorial(int n) { long long int resultado; if (n == 0) { // Caso base resultado = 1; } else { resultado = n * factorial(n – 1); } return resultado; } (Gp:) N x Factorial(N-1) si N > 0 (Gp:) Factorial(N) (Gp:) 1 si N = 0
Algoritmos recursivos Funciones recursivas long long int factorial(int n) { long long int resultado; if (n == 0) { // Caso base resultado = 1; } else { resultado = n * factorial(n – 1); } return resultado; } factorial(5) ? 5 x factorial(4) ? 5 x 4 x factorial(3) ? 5 x 4 x 3 x factorial(2) ? 5 x 4 x 3 x 2 x factorial(1) ? 5 x 4 x 3 x 2 x 1 x factorial(0) ? 5 x 4 x 3 x 2 x 1 x 1 ? 120 (Gp:) Caso base
Algoritmos recursivos Diseño de funciones recursivas Una función recursiva debe satisfacer tres condiciones: Caso(s) base: Debe haber al menos un caso base de parada Inducción: Paso recursivo que provoca una llamada recursiva Debe ser correcto para distintos parámetros de entrada Convergencia: Cada paso recursivo debe acercar a un caso base Se describe el problema en términos de problemas más sencillos
Función factorial(): tiene caso base (N = 0), siendo correcta para N es correcta para N+1 (inducción) y se acerca cada vez más al caso base (N-1 está más cerca de 0 que N) (Gp:) N x Factorial(N-1) si N > 0 (Gp:) Factorial(N) (Gp:) 1 si N = 0
Modelo de ejecución long long int factorial(int n) { long long int resultado; if (n == 0) { // Caso base resultado = 1; } else { resultado = n * factorial(n – 1); } return resultado; } Cada llamada recursiva fuerza una nueva ejecución de la función Cada llamada utiliza sus propios parámetros por valor y variables locales (n y resultado en este caso) En las llamadas a la función se utiliza la pila del sistema para mantener los datos locales y la dirección de vuelta
La pila del sistema (stack) Regiones de memoria que distingue el sistema operativo:
(Gp:) Llamadas a subprogramas
(Gp:) Memoria dinámica (Tema 9)
(Gp:) Memoria principal
La pila del sistema (stack) Mantiene los datos locales de la función y la dirección de vuelta Estructura de tipo pila: lista LIFO (last-in first-out) El último que entra es el primero que sale:
Entra4 Entra7 Entra 2 Sale 2
La pila y las llamadas a función Datos locales y direcciones de vuelta … int funcB(int x) { … return x; } int funcA(int a) { int b; … b = funcB(a); … return b; } int main() { … cout << funcA(4); … Pila
(Gp:) Llamada a función: Entra la dirección de vuelta
Datos locales y direcciones de vuelta … int funcB(int x) { … return x; } int funcA(int a) { int b; … b = funcB(a); … return b; } int main() { … cout << funcA(4); … La pila y las llamadas a función Pila
(Gp:) Entrada en la función: Se alojan los datos locales
Datos locales y direcciones de vuelta … int funcB(int x) { … return x; } int funcA(int a) { int b; … b = funcB(a); … return b; } int main() { … cout << funcA(4); … La pila y las llamadas a función Pila
(Gp:) Llamada a función: Entra la dirección de vuelta
Datos locales y direcciones de vuelta … int funcB(int x) { … return x; } int funcA(int a) { int b; … b = funcB(a); … return b; } int main() { … cout << funcA(4); … La pila y las llamadas a función Pila
(Gp:) Entrada en la función: Se alojan los datos locales
Datos locales y direcciones de vuelta … int funcB(int x) { … return x; } int funcA(int a) { int b; … b = funcB(a); … return b; } int main() { … cout << funcA(4); … La pila y las llamadas a función Pila
(Gp:) Vuelta de la función: Se eliminan los datos locales
Datos locales y direcciones de vuelta … int funcB(int x) { … return x; } int funcA(int a) { int b; … b = funcB(a); … return b; } int main() { … cout << funcA(4); … La pila y las llamadas a función Pila
(Gp:) Vuelta de la función: Sale la dirección de vuelta
Datos locales y direcciones de vuelta … int funcB(int x) { … return x; } int funcA(int a) { int b; … b = funcB(a); … return b; } int main() { … cout << funcA(4); … La pila y las llamadas a función Pila
(Gp:) La ejecución continúaen esa dirección
Recursión simple Sólo hay una llamada recursiva Ejemplo: Cálculo del factorial de un número entero positivo long long int factorial(int n) { long long int resultado; if (n == 0) { // Caso base resultado = 1; } else { resultado = n * factorial(n – 1); } return resultado; }
(Gp:) Una sola llamada recursiva
Página siguiente |