Programación Recursiva: Guía completa con ejemplos prácticos
¿Has visto esas escenas de película donde alguien se para frente a dos espejos paralelos y aparecen infinitas versiones de sí mismo desapareciendo en la distancia? Eso, amigos, es la recursión en la vida real. La primera vez que me topé con este concepto en programación pensé "esto tiene que ser brujería", pero resulta que es una de las técnicas más elegantes y poderosas que existen.
La recursión: cuando una función se hace amiga de sí misma
La recursión es básicamente cuando una función se llama a sí misma para resolver un problema. Suena loco, ¿verdad? Es como decirle a alguien "para llegar a tu casa, primero llega a tu casa". Pero en realidad tiene mucho sentido cuando lo ves en acción.
La clave está en dividir un problema grande en pedacitos más pequeños, como pelar una cebolla capa por capa hasta llegar al centro. Cada "capa" es una versión más pequeña del mismo problema.
Los tres elementos que no pueden faltar (nunca)
Para que una función recursiva funcione y no se vuelva loca, necesita estos tres ingredientes:
- Caso base: El momento donde dice "ok, ya llegué, aquí paro"
- Caso recursivo: Donde se llama a sí misma con una versión más pequeña del problema
- Progresión: Cada llamada tiene que acercarte más al final, no alejarte
El clásico de los clásicos: el factorial
Cuando aprendes recursión, es casi obligatorio empezar con el factorial. Es como el "Hello World" del mundo recursivo:
// JavaScript
function factorial(n) {
// Caso base
if (n <= 1) {
return 1;
}
// Caso recursivo
return n * factorial(n - 1);
}
console.log(factorial(5)); // 120
# Python
def factorial(n):
# Caso base
if n <= 1:
return 1
# Caso recursivo
return n * factorial(n - 1)
print(factorial(5)) # 120
Cómo se desenrolla esta magia
Es como construir una torre de cartas: primero apilas todo hacia arriba, y luego se va resolviendo de vuelta hacia abajo.
Ejemplos que realmente vas a usar
1. La secuencia de Fibonacci (que aparece en la naturaleza)
// JavaScript
function fibonacci(n) {
if (n <= 1) {
return n;
}
return fibonacci(n - 1) + fibonacci(n - 2);
}
console.log(fibonacci(7)); // 13
# Python
def fibonacci(n):
if n <= 1:
return n
return fibonacci(n - 1) + fibonacci(n - 2)
print(fibonacci(7)) # 13
2. Sumar arrays sin bucles (porque podemos)
// Suma de elementos en un array
function sumaArray(arr, index = 0) {
// Caso base
if (index >= arr.length) {
return 0;
}
// Caso recursivo
return arr[index] + sumaArray(arr, index + 1);
}
console.log(sumaArray([1, 2, 3, 4, 5])); // 15
3. Buscar en objetos anidados (súper útil)
// Buscar en un objeto anidado
function buscarEnObjeto(obj, clave) {
for (let key in obj) {
if (key === clave) {
return obj[key];
}
if (typeof obj[key] === 'object') {
const resultado = buscarEnObjeto(obj[key], clave);
if (resultado !== undefined) {
return resultado;
}
}
}
return undefined;
}
const datos = {
usuario: {
perfil: {
nombre: "Juan",
configuracion: {
tema: "oscuro"
}
}
}
};
console.log(buscarEnObjeto(datos, "tema")); // "oscuro"
Algoritmos recursivos que te van a volar la cabeza
1. Las Torres de Hanoi (un rompecabezas milenario)
function torresHanoi(n, origen, destino, auxiliar) {
if (n === 1) {
console.log(`Mover disco de ${origen} a ${destino}`);
return;
}
torresHanoi(n - 1, origen, auxiliar, destino);
console.log(`Mover disco de ${origen} a ${destino}`);
torresHanoi(n - 1, auxiliar, destino, origen);
}
torresHanoi(3, "A", "C", "B");
2. Recorrer árboles como un explorador
class Nodo {
constructor(valor) {
this.valor = valor;
this.izquierda = null;
this.derecha = null;
}
}
function recorridoInOrden(nodo) {
if (nodo === null) {
return;
}
recorridoInOrden(nodo.izquierda);
console.log(nodo.valor);
recorridoInOrden(nodo.derecha);
}
// Crear árbol
const raiz = new Nodo(4);
raiz.izquierda = new Nodo(2);
raiz.derecha = new Nodo(6);
raiz.izquierda.izquierda = new Nodo(1);
raiz.izquierda.derecha = new Nodo(3);
recorridoInOrden(raiz); // 1, 2, 3, 4, 6
3. Generar todas las combinaciones posibles
function generarPermutaciones(arr) {
if (arr.length <= 1) {
return [arr];
}
const permutaciones = [];
for (let i = 0; i < arr.length; i++) {
const elemento = arr[i];
const resto = arr.slice(0, i).concat(arr.slice(i + 1));
const subPermutaciones = generarPermutaciones(resto);
for (let subPerm of subPermutaciones) {
permutaciones.push([elemento].concat(subPerm));
}
}
return permutaciones;
}
console.log(generarPermutaciones([1, 2, 3]));
// [[1,2,3], [1,3,2], [2,1,3], [2,3,1], [3,1,2], [3,2,1]]
La eterna batalla: recursión vs bucles
El dilema de rendimiento
// Recursivo (menos eficiente)
function fibonacciRecursivo(n) {
if (n <= 1) return n;
return fibonacciRecursivo(n - 1) + fibonacciRecursivo(n - 2);
}
// Iterativo (más eficiente)
function fibonacciIterativo(n) {
if (n <= 1) return n;
let a = 0, b = 1;
for (let i = 2; i <= n; i++) {
[a, b] = [b, a + b];
}
return b;
}
Cuándo usar cada uno (mi guía personal)
| Usar Recursión | Usar Iteración | |----------------|-----------------| | Estructuras de datos jerárquicas | Bucles simples | | Problemas naturalmente recursivos | Rendimiento crítico | | Divide y vencerás | Uso de memoria limitado | | Backtracking | Casos base complejos |
Trucos para hacer la recursión más eficiente
1. Memoización (la técnica que salva vidas)
function fibonacciMemoizado(n, memo = {}) {
if (n in memo) {
return memo[n];
}
if (n <= 1) {
return n;
}
memo[n] = fibonacciMemoizado(n - 1, memo) + fibonacciMemoizado(n - 2, memo);
return memo[n];
}
2. Recursión de cola (para los perfeccionistas)
function factorialCola(n, acumulador = 1) {
if (n <= 1) {
return acumulador;
}
return factorialCola(n - 1, n * acumulador);
}
Los errores que todos cometemos (y cómo evitarlos)
1. El temido Stack Overflow
// ❌ Problema: Falta caso base
function problematico(n) {
return 1 + problematico(n - 1); // Stack overflow
}
// ✅ Solución: Agregar caso base
function corregido(n) {
if (n <= 0) return 0; // Caso base
return 1 + corregido(n - 1);
}
2. La recursión infinita (el infierno del programador)
// ❌ Problema: No progresa hacia el caso base
function infinita(n) {
if (n === 0) return 1;
return infinita(n); // No cambia n
}
// ✅ Solución: Progresar hacia el caso base
function finita(n) {
if (n === 0) return 1;
return finita(n - 1); // Decrementa n
}
Lo que he aprendido usando recursión en proyectos reales
Ojo que la recursión no es solo un ejercicio académico. En mi experiencia, es súper útil para:
- Navegación de menús anidados - Cuando tienes categorías dentro de categorías
- Procesamiento de comentarios - Respuestas a respuestas en redes sociales
- Análisis de archivos - Recorrer directorios y subdirectorios
- Algoritmos de búsqueda - Como el famoso divide y vencerás
- Validación de formularios complejos - Campos que dependen de otros campos
Lo importante es recordar que la recursión brilla cuando el problema naturalmente se puede dividir en subproblemas idénticos pero más pequeños. Si te encuentras forzando una solución recursiva cuando un bucle sería más simple, probablemente estés complicándote la vida.
Una cosa que me costó entender al principio es que la recursión requiere un cambio de mentalidad. En lugar de pensar "¿cómo resuelvo todo el problema?", piensas "¿cómo resuelvo un paso y confío en que el resto se resuelve solo?".
En mi experiencia, una vez que haces "clic" con la recursión, empiezas a ver patrones recursivos en todos lados. Es como cuando aprendes una palabra nueva y de repente la escuchas en todas partes.
¿Has usado recursión en algún proyecto? ¿Cuál fue tu primera experiencia tratando de entender cómo una función se puede llamar a sí misma? ¿O tienes algún problema que crees que podría resolverse elegantemente con recursión? Me encanta escuchar las historias de otros developers con este concepto que al principio parece tan abstracto pero que termina siendo súper práctico.
Comentarios
Posts relacionados

¿Qué son las Expresiones Regulares? Guía completa
Domina las expresiones regulares (regex) desde cero. Aprende su sintaxis, patrones comunes y casos de uso prácticos con ejemplos detallados.

Map vs forEach en JavaScript: Cuándo y Cómo Utilizarlos
Diferencias entre map y forEach en JavaScript, con ejemplos prácticos y casos de uso