Saltar a contenido

♾️ Recursividad en Java

🧠 ¿Qué es la recursividad?

La recursividad es una técnica de programación en la que un método se llama a sí mismo para resolver un problema. Cada llamada debe acercarse un poco más a la solución final, hasta llegar a un caso base que detiene el proceso.

💬 En resumen: Un método recursivo es aquel que se repite a sí mismo, pero con un problema cada vez más pequeño, hasta que ya no necesita seguir repitiéndose.


🪜 Estructura básica de un método recursivo

public static void metodoRecursivo() {
    // 1️⃣ Caso base: condición que detiene la recursión
    if (condición_de_parada) {
        return;
    }

    // 2️⃣ Caso recursivo: llamada al propio método con un problema más pequeño
    metodoRecursivo();
}

🔍 Ejemplo sencillo: contar hacia atrás

public static void cuentaAtras(int n) {
    if (n < 0) return; // 🛑 Caso base
    System.out.println(n);
    cuentaAtras(n - 1); // 🔁 Llamada recursiva
}

📤 Llamada:

cuentaAtras(5);

📥 Salida:

5
4
3
2
1
0


⚙️ Cómo funciona paso a paso

📈 Ejemplo visual:
cuentaAtras(3) se ejecuta así:

Llamada Acción Próxima llamada
cuentaAtras(3) imprime 3 llama a cuentaAtras(2)
cuentaAtras(2) imprime 2 llama a cuentaAtras(1)
cuentaAtras(1) imprime 1 llama a cuentaAtras(0)
cuentaAtras(0) imprime 0 termina ✅

💡 Importante: la recursión crea una pila de llamadas (stack).
Cada llamada espera a que la siguiente termine antes de continuar.


🚫 Peligro: recursión infinita

Si olvidas el caso base, el método nunca se detiene y provocará un error de tipo:

java.lang.StackOverflowError

⚠️ Ejemplo incorrecto:

public static void infinito() {
    System.out.println("Hola");
    infinito(); // ❌ No hay caso base
}

🧩 Ejemplo clásico: factorial

El factorial de un número (n!) se define como:

n! = n × (n-1) × (n-2) × ... × 1

En Java con recursividad:

public static int factorial(int n) {
    if (n == 0) return 1;        // 🛑 Caso base
    return n * factorial(n - 1); // 🔁 Llamada recursiva
}

📤 Llamada:

System.out.println(factorial(5));

📥 Salida:

120

📚 Proceso interno:

factorial(5)
= 5 * factorial(4)
= 5 * 4 * factorial(3)
= 5 * 4 * 3 * factorial(2)
= 5 * 4 * 3 * 2 * factorial(1)
= 5 * 4 * 3 * 2 * 1
= 120 ✅

🧮 Otro ejemplo: suma de números

Sumar los números del 1 al n:

public static int sumaRecursiva(int n) {
    if (n == 1) return 1; // 🛑 Caso base
    return n + sumaRecursiva(n - 1); // 🔁
}

🧭 Cuándo usar recursividad

Úsala cuando:
- El problema pueda dividirse en subproblemas más pequeños del mismo tipo.
- Sea más natural o legible escribirlo de forma recursiva (por ejemplo, árboles o laberintos).
- No sepas cuántas iteraciones necesitas (la profundidad depende del problema).

Evítala cuando:
- Puedas resolverlo fácilmente con un bucle (for, while).
- La recursión sea muy profunda (puede agotar la memoria de la pila).
- Necesites máxima eficiencia en rendimiento.


🌳 Ejemplo visual: árbol de llamadas

Ejemplo para factorial(4):

factorial(4)
    4 * factorial(3)
        3 * factorial(2)
            2 * factorial(1)
                1 * factorial(0)
                    return 1
                return 1 * 1 --> 1   
            return 2 * 1 --> 2
        return 3 * 2 --> 6 
    return 4 * 6 --> 24
return 24

Ejemplo: Verificar si un número es palíndromo

Un número es palíndromo si al leerse en ambos sentidos, tanto de izquierda a derecha como de derecha a izquierda, se obtiene el mismo número. Por ejemplo: 121, 1001, etc.

public static int revertir(int n, int reverso) {
    if (n > 0) {
        int ud = n % 10;
        reverso = reverso * 10;
        return revertir(n/10, ud+reverso);
    } else {
        return reverso;
    }
}

public static void main (String[] args) {
    int reverso = revertir(121, 0);

    if (reverso == n)
        System.out.println("Son palíndromos.");
    else
        System.out.println("No lo son" );
}

Ejemplo: Revertir un String

Para revertir un String, nos quedamos con el primer carácter que iremos añadiendo al final de la recursividad, y vamos acortando el String para llegar al caso base.

public static String reverseRecursive(String str) {
    if (str.isEmpty()) { //caso base
        return "";
    }
    return reverseRecursive(str.substring(1)) + str.charAt(0);
}

🧠 Resumen final

Concepto Descripción
🪞 Recursividad Un método se llama a sí mismo.
🧱 Caso base Condición que detiene la recursión.
🔁 Caso recursivo Llamada al método con un problema más pequeño.
🧮 Ejemplo típico Factorial, potencias, sumas, conteos.
⚠️ Error común No definir un caso base → StackOverflowError.

🔁 Recursividad vs Iteración

Aunque la recursividad y la iteración pueden parecer distintas, ambas son formas de repetir acciones.
De hecho, todo método iterativo puede expresarse de forma recursiva, aunque no siempre sea lo más eficiente.

✅ En teoría

Cualquier bucle (for, while) puede convertirse en un método recursivo equivalente.

// Versión iterativa
for (int i = 1; i <= 5; i++) {
    System.out.println(i);
}

// Versión recursiva
public static void imprimir(int i) {
    if (i > 5) return; // 🛑 Caso base
    System.out.println(i);
    imprimir(i + 1);   // 🔁 Llamada recursiva
}

⚙️ En la práctica

Aspecto Iterativo Recursivo
🔁 Repetición Usa bucles (for, while) Se llama a sí mismo
💾 Memoria Usa una sola pila de ejecución Crea una nueva pila por llamada
🚀 Velocidad Suele ser más eficiente Puede ser más lenta si hay muchas llamadas
🧠 Legibilidad Más directa en problemas simples Más clara en estructuras jerárquicas (árboles, laberintos, etc.)

🧩 Cuándo elegir una u otra

Usa recursividad cuando:
- El problema se puede dividir en subproblemas similares (divide y vencerás).
- Trabajas con estructuras jerárquicas o anidadas (carpetas, árboles, fractales).
- El código resulta más legible y natural recursivamente.

Prefiere la iteración cuando:
- El proceso es lineal o repetitivo (sumas, bucles simples).
- Buscas eficiencia y bajo consumo de memoria.
- La recursión puede ser muy profunda (riesgo de StackOverflow).


🧭 ¿Por qué la recursividad es importante?

1️⃣ Porque enseña a pensar de otra forma

La recursividad no solo es una técnica: es una forma de razonar sobre los problemas.

Te obliga a:
- Dividir un problema grande en subproblemas más pequeños del mismo tipo.
- Pensar en términos de auto-referencia (“¿cómo resolvería una versión más simple de esto?”).

💬 En programación, aprender recursividad entrena el pensamiento algorítmico.
Es una habilidad mental que luego aplicas incluso en problemas iterativos.


2️⃣ Porque hay problemas que son naturalmente recursivos Hay estructuras o algoritmos donde la recursividad no solo es elegante, sino natural.


3️⃣ Porque mejora la claridad del código

Una función recursiva bien escrita puede ser más corta, más expresiva y más fácil de leer que su versión iterativa.

Por ejemplo, recorrer un árbol con bucles requeriría estructuras auxiliares (pilas, colas, etc.), mientras que recursivamente basta con llamar al mismo método sobre los hijos del nodo.


4️⃣ Porque forma parte del lenguaje universal de los algoritmos

En programación, inteligencia artificial, teoría de lenguajes o matemáticas computacionales, la recursividad es una herramienta base.

Lenguajes como Python, Lisp, Haskell, Prolog o frameworks modernos de JavaScript (React, por ejemplo) usan estructuras y conceptos basados en funciones recursivas o auto-referenciales.


5️⃣ Porque ayuda a entender la memoria y la pila de ejecución

Cada llamada recursiva ocupa un espacio en la pila de ejecución (stack). Comprender cómo funciona ayuda a entender:
- cómo se gestionan las variables locales,
- qué es un StackOverflowError,
- y cómo los lenguajes manejan el flujo de ejecución.

Es decir, estudiar recursividad te enseña cómo funciona el programa “por dentro”.