Una función recursiva se define en términos de sí misma. Resuelve un problema grande dividiéndolo en instancias más pequeñas del mismo tipo, hasta alcanzar un caso base que detiene el proceso.
Hasta ahora hemos estudiado funciones que se definen mediante fórmulas directas o tablas de valores. Sin embargo, muchos problemas discretos se describen de forma natural como **repetición de un mismo patrón sobre un tamaño decreciente**.
La **recursión** es el mecanismo matemático y computacional que formaliza esta idea: una función recursiva resuelve un problema invocándose a sí misma con una entrada más simple, hasta llegar a un **caso base** que puede resolverse directamente sin nuevas llamadas.
Una función f definida sobre un subconjunto de los enteros no negativos (o sobre otro dominio ordenado) es **recursiva** si su definición incluye dos partes:
La función g combina el valor actual n con el resultado de la llamada recursiva f(n − 1). Cada llamada reduce el problema hacia el caso base, garantizando que el proceso termine en un número finito de pasos.
El **caso base** es indispensable: sin él, la función seguiría llamándose indefinidamente. En programación esto produce un error de **desbordamiento de pila** (stack overflow).
La **condición de terminación** es la regla que decide cuándo dejar de hacer llamadas recursivas y devolver un valor directo. Por ejemplo, en el factorial:
Cada llamada a factorial(n) con n > 0 delega el trabajo a factorial(n − 1), acercándose en una unidad al caso base en cada paso.
El simulador muestra cómo el intérprete gestiona las llamadas recursivas mediante una **pila de activación**. Cada nueva llamada apila un marco (frame) con el valor del parámetro; al retornar, el marco se desapila y el resultado sube al llamador. Usa **Siguiente Paso** para avanzar paso a paso o **Reproducir** para ver la animación completa.
Factorial: cuenta las permutaciones de n elementos distintos.
Suma de los primeros n enteros positivos:
Ambas funciones comparten la misma estructura: un caso base que detiene la recursión y un paso que reduce el problema en una unidad.
En JavaScript, una función recursiva se implementa haciendo que el cuerpo de la función invoque a la misma función con un argumento más pequeño, siempre verificando primero el caso base. Todo algoritmo recursivo finito puede reescribirse con un bucle (versión iterativa), pero la forma recursiva suele reflejar mejor la definición matemática.
// Factorial recursivo
function factorial(n) {
if (n === 0) return 1; // caso base
return n * factorial(n - 1); // caso recursivo
}
// Suma recursiva de 1 + 2 + ... + n
function suma(n) {
if (n === 0) return 0; // caso base
return n + suma(n - 1); // caso recursivo
}
console.log("factorial(5) =", factorial(5)); // 120
console.log("suma(5) =", suma(5)); // 15
// Versión iterativa equivalente del factorial (para comparar)
function factorialIterativo(n) {
let resultado = 1;
for (let i = 2; i <= n; i++) {
resultado *= i;
}
return resultado;
}
console.log("factorialIterativo(5) =", factorialIterativo(5)); // 120
f(n - 2) cuando el caso base es f(0) puede saltarse valores y no terminar correctamente; o llamar a f(n + 1) aleja la entrada del caso base.for que repite una operación no es recursión; la recursión requiere que la función se invoque a sí misma.Las funciones recursivas modelan problemas que se repiten a escala decreciente: desde contar combinaciones hasta recorrer estructuras anidadas. Comprender la pila de llamadas es clave para depurar programas recursivos y anticipar límites de memoria.
En el próximo tema estudiaremos las **sucesiones y progresiones discretas**, analizando cómo los términos de una lista ordenada evolucionan según reglas aritméticas o geométricas, y cómo se conectan con las definiciones recursivas que acabamos de ver.