Complejidad de la Recursión
Aprende a analizar la complejidad temporal y espacial de funciones recursivas
¿Por qué analizar la recursión?
Cuando escribes una función recursiva, necesitas saber: ¿cuánto tiempo tarda? ¿cuánta memoria usa? Esto es especialmente importante en competencias, donde hay límites estrictos de tiempo y memoria.
Método 1: Árbol de recursión
Dibuja todas las llamadas como un árbol y cuenta:
Factorial:
factorial(5)
└── factorial(4)
└── factorial(3)
└── factorial(2)
└── factorial(1)
└── factorial(0) ← caso base
Es una cadena lineal de llamadas. Cada llamada hace trabajo. Total: .
Fibonacci (sin memo):
fib(5)
├── fib(4)
│ ├── fib(3)
│ │ ├── fib(2) ──...
│ │ └── fib(1)
│ └── fib(2) ──...
└── fib(3)
├── fib(2) ──...
└── fib(1)
Es un árbol binario de profundidad . Tiene hasta nodos. Total: .
Fibonacci (con memo):
Cada valor de 0 a n se calcula exactamente una vez. Total: .
Método 2: Relación de recurrencia
Expresa el tiempo como una fórmula recursiva y resuélvela:
Ejemplo: Búsqueda binaria
int busqueda(vector<int> &v, int lo, int hi, int x) {
if (lo > hi) return -1;
int mid = (lo + hi) / 2;
if (v[mid] == x) return mid;
if (v[mid] < x) return busqueda(v, mid+1, hi, x);
return busqueda(v, lo, mid-1, x);
}
Recurrencia:
En cada llamada, el problema se reduce a la mitad. Después de pasos, , así que .
Total: .
Ejemplo: Merge Sort
void mergeSort(vector<int> &v, int lo, int hi) {
if (lo >= hi) return;
int mid = (lo + hi) / 2;
mergeSort(v, lo, mid); // Primera mitad
mergeSort(v, mid+1, hi); // Segunda mitad
merge(v, lo, mid, hi); // Combinar: O(n)
}
Recurrencia:
Dos subproblemas de tamaño , más para combinar. Total: .
Recurrencias comunes
| Recurrencia | Complejidad | Ejemplo |
|---|---|---|
| Factorial, búsqueda lineal recursiva | ||
| Selection sort recursivo | ||
| Fibonacci, torres de Hanoi | ||
| Búsqueda binaria | ||
| Merge sort | ||
| Recorrer árbol binario |
Complejidad espacial
La recursión usa espacio en la pila de llamadas. La profundidad máxima de la pila = la profundidad del árbol de recursión.
| Función | Profundidad de recursión | Espacio |
|---|---|---|
| Factorial | ||
| Fibonacci (sin memo) | ||
| Búsqueda binaria | ||
| Merge sort | (por el arreglo auxiliar) |
Consejos prácticos
-
Si la recursión es lineal (una sola llamada recursiva por nivel), la complejidad suele ser simple de analizar.
-
Si hay dos llamadas recursivas (como Fibonacci), la complejidad crece exponencialmente sin memorización.
-
Con memorización, la complejidad es: (número de estados) × (trabajo por estado).
-
En competencias, si , puedes usar . Si , necesitas o .
Ejercicio de práctica
Analiza la complejidad de esta función. ¿Cuántas veces se imprime "hola"?
void misterio(int n) {
if (n <= 0) return;
cout << "hola" << endl;
misterio(n / 3);
misterio(n / 3);
}
Ver solución
Usando el teorema maestro con , , : como , la complejidad es .
En términos simples: crece más rápido que pero mucho más lento que .
Siguiente paso
Aprende sobre Pilas y Colas, estructuras de datos fundamentales que tienen conexión directa con la recursión.
