6.2.5
Ejemplos de aplicación: 01
Heaps
Un heap es un árbol binario de una
forma especial, que permite su almacenamiento en un arreglo sin usar punteros.
Un heap tiene todos sus niveles llenos,
excepto posiblemente el de más abajo, y en este último los nodos están lo más a
la izquierda posible.
Ejemplo:

La numeración por niveles (indicada
bajo cada nodo) son los subíndices en donde cada elemento sería almacenado en
el arreglo. En el caso del ejemplo, el arreglo sería:

La característica que permite que un
heap se pueda almacenar sin punteros es que, si se utiliza la numeración por
niveles indicada, entonces la relación entre padres e hijos es:
Hijos del nodo j
= {2*j, 2*j+1}
Padre del nodo k = floor(k/2)
Un heap puede utilizarse para
implementar una cola de prioridad almacenando los datos de modo que las llaves
estén siempre ordenadas de arriba a abajo (a diferencia de un árbol de búsqueda
binaria, que ordena sus llaves de izquierda a derecha). En otras palabras, el
padre debe tener siempre mayor prioridad que sus hijos (ver ejemplo).
Implementación
de las operaciones básicas
Inserción:
La inserción se realiza agregando el
nuevo elemento en la primera posición libre del heap, esto es, el próximo nodo
que debería aparecer en el recorrido por niveles o, equivalentemente, un
casillero que se agrega al final del arreglo.
Después de agregar este elemento, la forma del heap se preserva, pero la
restricción de orden no tiene por qué cumplirse. Para resolver este problema,
si el nuevo elemento es mayor que su padre, se intercambia con él, y ese
proceso se repite mientras sea necesario. Una forma de describir esto es
diciendo que el nuevo elemento "trepa" en el árbol hasta alcanzar el
nivel correcto según su prioridad.

El siguiente trozo de programa muestra
el proceso de inserción de un nuevo elemento x:
a[++n]=x;
for(j=n; j>1 && a[j]>a[j/2]; j/=2)
{ # intercambiamos con el padre
t=a[j];
a[j]=a[j/2];
a[j/2]=t;
}
El proceso de inserción, en el peor
caso, toma un tiempo proporcional a la altura del árbol, esto es, O(log
n).
Extracción
del máximo
El máximo evidentemente está en la raíz
del árbol (casillero 1 del arreglo). Al sacarlo de ahí, podemos imaginar que
ese lugar queda vacante. Para llenarlo, tomamos al último elemento del heap y lo trasladamos al lugar vacante. En
caso de que no esté bien ahí de acuerdo a su prioridad (¡que es lo más
probable!), lo hacemos descender intercambiándolo siempre con el mayor de sus
hijos. Decimos que este elemento "se hunde" hasta su nivel de
prioridad.