Dificultad: ★★★☆☆
Un sótano olvidado de la Torre entregó un cofre con cientos de presagios nunca catalogados, todos mezclados sin ningún orden. Un aprendiz impaciente propuso insertarlos uno por uno, tal como se enseña siempre; pero el Archivista Insomne, que ha visto cofres como este durante siglos, sonrió con algo parecido a la lástima. Hay una forma más rápida, y nadie que la aprende vuelve a mirar una inserción repetida de la misma manera.
Enunciado
- Método ingenuo: insertar los
npresagios uno por uno en un montículo inicialmente vacío, como en el Ejercicio 1. ¿Cuál es la complejidad total en el peor caso? Justificar. - Método “desde abajo”: en lugar de insertar de a uno, aplicar
sift-downempezando por el último nodo interno del arreglo (el último nodo que tiene al menos un hijo) y retrocediendo hasta la raíz. Describir el algoritmo en palabras. ¿Por qué alcanza con arrancar en el último nodo interno, sin procesar las hojas? - Trazar a mano el método “desde abajo” sobre el arreglo
[4, 18, 9, 25, 1, 30, 12, 7, 22, 15], mostrando el arreglo completo después de aplicarsift-downsobre cada nodo interno procesado. - Formalizar el argumento de complejidad del método “desde abajo”: plantear la suma que acota el costo total, pensando en cuántos nodos hay a cada altura del árbol y cuánto cuesta el
sift-downde un nodo según su altura. Mostrar que esa suma converge a . (No hace falta una demostración completamente rigurosa, pero sí identificar la serie involucrada y explicar por qué converge a una constante.)
Susurro del Archivista Insomne. Un montículo de
nelementos tiene aproximadamenten/2hojas (altura 0, costo desift-downnulo),n/4nodos de altura 1,n/8de altura 2, y así sucesivamente. El costo desift-downsobre un nodo depende de la altura de ese nodo, no de la altura total del árbol. Sumá, para cada altura, la cantidad de nodos que hay multiplicada por el costo de esa altura.
Reflexión Trampa. Reconciliá tu resultado del punto 4 con este razonamiento, que suena razonable pero no lo es: “El método ‘desde abajo’ hace del orden de
noperaciones desift-down, cada una de costo hasta en el peor caso… eso debería dar en total, igual que insertar uno por uno.” ¿Dónde está el error de esa cuenta? ¿Por qué sobreestima el costo real?
Ver solución
1. Método ingenuo
Insertar el -ésimo elemento en un montículo que ya tiene elementos cuesta, en el peor caso, un sift-up que recorre la altura del árbol: .
(por la aproximación de Stirling, o simplemente porque cada una de las inserciones cuesta a lo sumo ). Cota ajustada, porque las últimas inserciones ocurren efectivamente sobre montículos de tamaño , con altura real .
2. Método “desde abajo”
Idea: en vez de construir el montículo agregando hojas y arreglando hacia arriba, se parte del arreglo tal cual y se “arregla hacia abajo” cada subárbol, de atrás para adelante.
Algoritmo:
- Ubicar el último nodo interno: índice (0-indexado).
- Para desde ese índice hasta : aplicar
sift-down(i).
Por qué no hace falta procesar las hojas: un sift-down compara un nodo contra sus hijos y hunde el valor si corresponde. Una hoja no tiene hijos, así que sift-down sobre una hoja es una operación vacía: cada hoja ya es, trivialmente, un montículo válido de un solo elemento. Además, el invariante clave es que cuando se procesa el nodo , sus dos subárboles hijos ya son montículos válidos (porque se procesaron antes, al ir de atrás hacia adelante); eso es justamente lo que garantiza la corrección de sift-down(i).
3. Traza
Sobre [4, 18, 9, 25, 1, 30, 12, 7, 22, 15]:
, índices –. Último nodo interno: .
| Nodo procesado (índice : valor) | Hijos comparados | Arreglo resultante |
|---|---|---|
| inicial | ∅ | [4,18,9,25,1,30,12,7,22,15] |
| hijo(9)=15 | [4,18,9,25,15,30,12,7,22,1] | |
| hijos(7)=7,(8)=22 → no baja | [4,18,9,25,15,30,12,7,22,1] | |
| hijos(5)=30,(6)=12 → baja con 30 | [4,18,30,25,15,9,12,7,22,1] | |
| hijos(3)=25,(4)=15 → baja con 25; sigue: hijos(7)=7,(8)=22 → baja con 22 | [4,25,30,22,15,9,12,7,18,1] | |
| hijos(1)=25,(2)=30 → baja con 30; sigue: hijos(5)=9,(6)=12 → baja con 12 | [30,25,12,22,15,9,4,7,18,1] |
Resultado final: [30, 25, 12, 22, 15, 9, 4, 7, 18, 1] (se verifica la propiedad de montículo en cada nodo).
4. Complejidad del método “desde abajo”
El costo de sift-down en un nodo depende de la altura de ese nodo (distancia hasta su hoja más lejana), no de la altura del árbol completo. Como sugiere el Archivista:
| Altura | # nodos | costo por nodo | contribución |
|---|---|---|---|
| (trivial) | |||
Sumando sobre todas las alturas ():
La serie es una serie aritmético-geométrica: converge (porque ) a un valor constante:
Por lo tanto . La clave es que la cantidad de nodos decrece exponencialmente a medida que crece su costo, así que el producto (nodos × costo) decrece también exponencialmente y la suma total queda acotada por una constante multiplicando .
Respuesta a la reflexión trampa
El error de ” operaciones × cada una = ” es multiplicar por la cota superior global (, que solo corresponde al nodo raíz) en vez de usar el costo real de cada nodo según su altura.
Casi todos los nodos () son hojas con costo , y la mitad de los internos () tienen altura con costo . Solo hay un nodo (la raíz) con costo genuinamente . Usar para los nodos ignora que la mayoría son mucho más baratos, y por eso sobreestima brutalmente.
Esto contrasta con la inserción uno por uno: ahí sí hay inserciones que ocurren sobre montículos de tamaño (las últimas), con costo real cada una. El peor caso no está concentrado en un solo nodo, sino distribuido en una fracción constante de las operaciones. Esa asimetría (dónde se concentran los casos caros) es la diferencia real entre y .