Atlasingeniería

Estructuras de datosComplejidadTema 2

Peor caso, promedio y amortizado no son lo mismo

Un algoritmo puede ser rápido casi siempre, lento para una entrada particular y aun así tener costo constante amortizado. Separar esas tres ideas evita promesas de rendimiento engañosas.

Para este tema conviene tener claro:Complejidad algorítmica, visualmente

Decir que una operación “normalmente es rápida” puede esconder tres afirmaciones distintas: que la mayoría de las entradas son fáciles, que el azar suele ayudar o que una operación cara ocurre muy pocas veces. Caso promedio y costo amortizado no son sinónimos.

Mejor y peor caso

En una búsqueda lineal, el mejor caso ocurre cuando el objetivo está primero: una sola comparación, Θ(1)\Theta(1). El peor ocurre cuando está último o no aparece: Θ(n)\Theta(n).

El peor caso da una garantía: ninguna entrada de tamaño nn puede obligar al algoritmo a hacer más que esa cota. Es especialmente importante cuando una demora excepcional rompe un límite de tiempo, congela una interfaz o deja vencer una operación.

Antes de seguir, predecí

Un arreglo dinámico duplica su capacidad al llenarse. ¿Cuánto cuesta una inserción?

El promedio necesita una distribución

El caso promedio necesita una distribución de probabilidades sobre las entradas. Si el objetivo de una búsqueda lineal está presente y es igualmente probable en cualquier posición, se hacen en promedio

1+2++nn=n+12\frac{1+2+\cdots+n}{n}=\frac{n+1}{2}

comparaciones. Sigue siendo Θ(n)\Theta(n), aunque la constante sea aproximadamente la mitad del peor caso.

Sin decir qué entradas son probables, “promedio” no está definido. Los datos reales rara vez son uniformes, y una distribución equivocada vuelve irrelevante el cálculo.

Quicksort, donde declarar el caso cambia todo

Quicksort muestra por qué conviene declarar el caso. Si cada pivote divide el arreglo en partes parecidas, hay logn\log n niveles con nn trabajo por nivel: Θ(nlogn)\Theta(n\log n). Si el pivote queda siempre en un extremo, aparecen nn niveles: Θ(n2)\Theta(n^2).

Elegir el pivote al azar no elimina el peor caso; lo vuelve muy improbable para entradas independientes del azar. La garantía sigue siendo cuadrática, mientras que el costo esperado es O(nlogn)O(n\log n). Son dos afirmaciones verdaderas sobre el mismo algoritmo.

El arreglo dinámico y su inserción cara

Un arreglo dinámico suele agregar elementos en O(1)O(1), pero cuando se llena necesita reservar un bloque mayor y copiar todo. Esa inserción particular cuesta O(n)O(n). ¿Cómo puede decirse entonces que agregar al final es constante?

La respuesta no usa probabilidades. Mira una secuencia completa de operaciones. Si la capacidad se duplica —1, 2, 4, 8— las copias totales antes de guardar nn elementos son

1+2+4+<2n.1+2+4+\cdots < 2n.

Amortizado: el total dividido por las operaciones

Las nn inserciones normales cuestan nn y todas las redimensiones juntas cuestan menos de 2n2n. El trabajo total es menor que 3n3n, así que dividido entre nn operaciones da una constante por inserción: O(1)O(1) amortizado.

Capacidad 1, un elemento. La primera inserción es directa.

1 / 6
Las celdas con punto son capacidad reservada y todavía vacía. Cada vez que se llena, la capacidad se duplica y hay que copiar lo que había: esa inserción cuesta O(n) y las siguientes vuelven a ser gratis.

No significa que cada llamada tarde lo mismo. Una puede copiar miles de elementos. Significa que no puede ocurrir muchas veces sin que antes hayan ocurrido suficientes operaciones baratas. Las operaciones comunes “pagan” de a poco la cara.

Promedio y amortizado no son lo mismo

El caso promedio promedia sobre entradas posibles y necesita supuestos probabilísticos. El análisis amortizado promedia sobre una secuencia, sin azar: garantiza un costo total incluso si un adversario elige las operaciones.

Una tabla hash suele tener acceso O(1)O(1) esperado bajo supuestos sobre la función hash. Un vector dinámico tiene inserción O(1)O(1) amortizada aunque la secuencia sea la peor imaginable. La palabra que acompaña al costo cambia qué se está garantizando.

Cuándo el amortizado no alcanza

El costo amortizado puede ser insuficiente cuando importa la latencia de cada operación. Un servidor que responde rápido 999 veces y se frena un segundo en la número 1000 quizá tenga buen promedio y mala experiencia.

En esos casos se reparte el trabajo caro entre varias operaciones, se reserva capacidad antes o se elige una estructura con peor caso acotado. El análisis asintótico no decide la arquitectura solo: hay que preguntar si importa el throughput total o el máximo de cada respuesta.

Cuál de los tres mirar

Peor casoPromedioAmortizado
Qué afirmaninguna operación supera estoel costo esperado sobre entradas al azarn operaciones seguidas cuestan esto en total
Depende denadauna distribución supuestanada: es una garantía
Sirve parasistemas con límite de latencia, tiempo real, seguridadestimar rendimiento típicoestructuras con redimensión o reorganización
Se rompe cuandonunca, es una cotaalguien elige las entradas a propósitoimporta cada operación por separado
Ejemplomergesort: O(n log n)quicksort: O(n log n)arreglo dinámico: O(1) por inserción
La fila resaltada es la que separa el promedio del amortizado, y es la que más se confunde: el promedio supone que nadie está eligiendo las entradas, y el amortizado no supone nada.
Más a fondo · formalLos tres métodos para demostrarlo

El análisis amortizado tiene tres técnicas, y todas prueban lo mismo de formas distintas.

El agregado es el que usa este post: se cuenta el costo total de nn operaciones y se divide por nn. Es el más simple y sólo sirve cuando todas las operaciones son parecidas.

El contable le asigna a cada operación un costo ficticio mayor que el real y guarda la diferencia como crédito sobre la estructura. Cada inserción barata paga 3 en vez de 1 y deja 2 ahorrados; cuando llega la redimensión, la paga con lo ahorrado. Hay que probar que el crédito nunca se vuelve negativo.

El potencial generaliza al anterior: se define una función Φ\Phi del estado de la estructura —para el arreglo dinámico, algo como 2elementoscapacidad2 \cdot \text{elementos} - \text{capacidad}— y el costo amortizado de cada operación es su costo real más el cambio de Φ\Phi. Las operaciones baratas suben el potencial y la cara lo consume.

Los tres dan el mismo resultado. El del potencial es el que se usa para estructuras más complicadas —splay trees, heaps de Fibonacci— donde no alcanza con contar.

Cierre

Cuando alguien diga “esta operación es O(1)O(1)”, la pregunta correcta es: ¿peor caso, esperado o amortizado? El peor caso promete un techo por operación; el promedio depende de una distribución; el amortizado limita una secuencia completa. Nombrar bien la garantía es parte de diseñar bien la estructura.

Autoevaluación

¿Lo entendiste?

«Agregar al final de un arreglo dinámico es O(1)». ¿Qué garantía es esa?
¿Cuál es la diferencia entre caso promedio y costo amortizado?
Elegir el pivote de quicksort al azar, ¿qué cambia?
Un servicio responde rápido 999 veces y se frena un segundo en la número 1000. Tiene buen costo amortizado. ¿Alcanza?