Algoritmos Recursivos

Conceptos base de recursión, seguimiento mediante pila, ejemplos clásicos y clasificación inicial de recurrencias.

11. Algoritmos Recursivos

Prerrequisito

Módulos 1–3: complejidad temporal, operaciones elementales, ciclos iterativos y conocimiento de pilas.

Un algoritmo recursivo es aquel que se llama a sí mismo como parte de su solución. A diferencia de los iterativos —que se analizan línea por línea—, los recursivos se siguen a través de ambientes de ejecución, también llamados marcos de pila.

La recursión está en la naturaleza: las muñecas rusas, los fractales, la definición del factorial. Su poder está en expresar soluciones complejas de forma elegante y concisa.

11.1 Ambientes de ejecución y la pila

Cada vez que un algoritmo recursivo se llama a sí mismo, el sistema crea un nuevo ambiente de ejecución y lo apila sobre los anteriores.

En ese ambiente se guardan:

  • Todos los parámetros recibidos en esa llamada.
  • Todas las variables locales declaradas en esa ejecución.
  • La dirección de retorno: el punto exacto del código al que hay que volver cuando esa llamada termine.

Mientras el ambiente no termine, todos los ambientes anteriores quedan suspendidos esperando en la pila. Por eso la recursión tiene un costo espacial relevante: cada ambiente consume memoria.

Regla de los casos base

El número de casos base debe ser IGUAL al número de llamados en el caso general. Si el caso general hace 2 llamados recursivos, se necesitan al menos 2 casos base. Si hace 3, se necesitan 3.

11.2 Estructura de un algoritmo recursivo

Todo algoritmo recursivo correcto tiene exactamente dos partes:

Estructura obligatoria de un algoritmo recursivo

Caso base o casos base

Es la condición de parada. Se resuelve directamente, sin llamado recursivo. Su costo en la ecuación de recurrencia siempre es una constante.

Caso general

Es la situación donde el problema se reduce a versiones más pequeñas de sí mismo mediante llamados recursivos. Aquí está la lógica de la reducción.

11.3 Ejemplo: Fibonacci

Fibonacci es la suma de los dos anteriores: . En Fibonacci, se requieren dos casos base no porque haya dos llamadas recursivas, sino porque la fórmula depende de dos valores iniciales.

Pseudocódigo

Fib
int Fib(E int n) {
  if (n=0) or (n=1) then
    f <- n # caso base: Fib(0)=0, Fib(1)=1
  else
    f <- Fib(n-1) + Fib(n-2) # caso general
  endif
  return f
}

Seguimiento con : el algoritmo primero resuelve (abre un ambiente), dentro de ese resuelve , y así hasta llegar a los casos base. El de cada nivel queda pendiente hasta que el izquierdo termine.

Diagrama en Mermaid — Fib(5)

Renderizando diagrama...

Sobre el costo

Fibonacci sin optimización recalcula los mismos subproblemas muchas veces. calcula dos veces. es enormemente ineficiente. Esto motiva la Programación Dinámica (Módulo 13).

Ecuación de recurrencia

Caso base 0
Caso base 1
Casos base
Caso general

11.4 Ejemplo: Torres de Hanói

Tres torres (origen, auxiliar, destino) y discos apilados de mayor a menor en el origen.

Reglas

Mover un disco a la vez, nunca poner uno más grande sobre uno más pequeño.

Estrategia recursiva: para mover discos del origen al destino:

  1. Mover los discos superiores del origen al auxiliar, usando destino como apoyo.
  2. Mover el disco más grande del origen al destino.
  3. Mover los discos del auxiliar al destino, usando origen como apoyo.

Pseudocódigo

TH
TH(E int n, E char o, E char a, E char d) {
  if (n = 1) then
    Print('mover disco del origen al destino') # caso base
  else
    TH(n-1, o, d, a) # mueve n-1 al auxiliar
    Print('mover disco del origen al destino')
    TH(n-1, a, o, d) # mueve n-1 al destino
  endif
}

Mermaid — Torres de Hanói con n=4

Renderizando diagrama...

Árbol de recursión: cada nivel del árbol tiene el doble de nodos que el anterior. Nivel 1 → , Nivel 2 → , Nivel 3 → , Nivel → . Cada nodo cuesta una constante: un movimiento.

Recurrencia
Caso base
Solución
Orden
Clasificación

Esta ecuación es de tipo 'Resta y serás vencido': con . El costo crece exponencialmente porque cada nivel duplica el número de llamadas.

11.5 Clasificación de ecuaciones de recurrencia

Antes de elegir el método de resolución, hay que identificar qué tipo de ecuación tenemos:

Clasificación de ecuaciones de recurrencia

TipoFormaIdentificadorEjemplo
Divide y vencerásDivisión en el llamadoMerge Sort, Búsqueda Binaria
Resta y vencerásResta en el llamado, Búsqueda secuencial recursiva
Resta y serás vencidoResta en el llamado, Torres de Hanói, Fibonacci
Regla

Toda ecuación de recurrencia DEBE tener caso general Y caso base. Sin caso base no hay parada. El caso base siempre tiene costo constante: , .

11.6 Recursión de cola

Una recursión es de cola cuando el llamado recursivo es lo último que ocurre en el caso general. En ese caso, el sistema puede convertirla en iteración automáticamente o manualmente porque no hay nada pendiente después del llamado.

Clave

Si un algoritmo recursivo es de cola, siempre conviene convertirlo a iterativo: misma lógica, costo espacial en lugar de por la pila.