Recursividad: funciones que se llaman a sí mismas
Caso base, caso recursivo y la pila de llamadas, con un visualizador de factorial, Fibonacci y Torres de Hanói.
Una función recursiva resuelve un problema resolviendo una versión más pequeña del mismo problema, hasta llegar a un caso tan simple que se responde directamente. Suena raro; con la pila de llamadas delante se ve claro.
Las dos partes de toda recursión
- Caso base: la condición que corta la recursión. Sin él, la función se llama para siempre → stack overflow.
- Caso recursivo: la función se llama a sí misma con un problema más pequeño, acercándose al caso base.
function factorial(n) {
if (n <= 1) return 1; // caso base
return n * factorial(n - 1); // caso recursivo
}
Visualizador de la pila de llamadas
Cada llamada pendiente es un marco apilado. Cuando una llamada devuelve, su marco se quita y el de abajo continúa. Elige una función y pulsa Ejecutar:
Cuidado con Fibonacci recursivo
fib(n) = fib(n-1) + fib(n-2) es elegante pero recalcula lo mismo una y otra vez: es O(2ⁿ). fib(40) ya tarda segundos. Se arregla guardando resultados (memoización) o con un bucle:
function fib(n, memo = {}) {
if (n < 2) return n;
if (memo[n]) return memo[n];
return memo[n] = fib(n - 1, memo) + fib(n - 2, memo); // ahora O(n)
}
Recursividad vs bucle
Todo lo recursivo se puede escribir con un bucle y viceversa. La recursión brilla cuando la estructura del problema ya es recursiva: árboles, carpetas dentro de carpetas, dividir y vencer.
# Recorrer una carpeta y sus subcarpetas: natural con recursión
import os
def listar(ruta, nivel=0):
for nombre in sorted(os.listdir(ruta)):
completa = os.path.join(ruta, nombre)
print(" " * nivel + nombre)
if os.path.isdir(completa):
listar(completa, nivel + 1) # el mismo problema, una carpeta más adentro
Comprueba lo aprendido
factorial(n) = n <= 1 ? 1 : n * factorial(n-1), ¿cuánto es factorial(4)?