Menu
Coddy logo textTech

Heap (montículo binario)

Última actualización

Un montículo binario es un árbol binario completo que mantiene el valor más pequeño (min-heap) o más grande (max-heap) en la raíz. Esta visualización es un min-heap: cada padre es menor o igual que sus hijos. Para añadir un valor lo agregas en la siguiente posición libre y luego lo "haces subir", intercambiándolo con su padre mientras sea menor, hasta que se cumpla de nuevo la propiedad de montículo. Pulsa reproducir arriba para ver cómo cada nuevo valor sube hasta su lugar.

Como un montículo es un árbol completo, se almacena de forma compacta en un arreglo: los hijos del nodo i están en 2i+1 y 2i+2. Insertar y quitar el mínimo son O(log n) (un camino de la raíz a una hoja), mientras que consultar el mínimo es O(1), que es justo lo que necesita una cola de prioridad.

Complejidad temporal y espacial

OperaciónComplejidadNotas
Consultar mín/máxO(1)Siempre es la raíz
Insertar (push)O(log n)Subir por un camino
Quitar mín/máxO(log n)Bajar por un camino
Construir el montículoO(n)Heapify de una vez
EspacioO(n)Basado en arreglo, sin punteros

Paso a paso (push)

PasoQué ocurre
1Agrega el nuevo valor al final (la siguiente hoja libre).
2Compáralo con su padre.
3Si es menor (min-heap), intercámbialo hacia arriba.
4Repite hasta que ya no sea menor que su padre o llegue a la raíz.

Ejemplo resuelto

Construyendo un min-heap insertando [5, 3, 8, 1, 4] un valor a la vez:

PushArreglo tras subirAcción
5[5]El primer valor pasa a ser la raíz.
3[3, 5]3 < padre 5, así que sube hasta la raíz.
8[3, 5, 8]8 > padre 5, así que se queda como hoja.
1[1, 3, 8, 5]1 < padre 5, intercambia; luego 1 < padre 3, sube hasta la raíz.
4[1, 3, 8, 5, 4]4 > padre 3, así que se queda; el mínimo 1 sigue en la raíz.

Cuándo usar un heap

Úsalo cuandoEvítalo cuando
Necesitas repetidamente el elemento más pequeño o más grande de un conjunto cambiante.Necesitas buscar valores arbitrarios, no solo el extremo: usa un BST o un conjunto hash.
Implementas una cola de prioridad para Dijkstra, A* o un planificador.Necesitas mantener los datos totalmente ordenados en todo momento.
Quieres inserción y extracción del mínimo en O(log n) con un arreglo compacto.Necesitas búsqueda o eliminación rápida de un elemento concreto (no la raíz).
Necesitas fusionar un flujo de elementos y extraerlos por prioridad.El conjunto de datos es diminuto y un recorrido lineal es más simple y suficientemente rápido.

Código de Heap (Priority Queue)

Una implementación limpia y ejecutable de Heap (Priority Queue) en Python, JavaScript, Java, C++, C. Elige un lenguaje, copia el código o ábrelo ya cargado en el Playground de Coddy.

Código de Heap (Priority Queue) en Python

Python
1class MinHeap:2    def __init__(self):3        self.data = []4
5    def push(self, value):6        # Append at the end, then bubble up to restore order7        self.data.append(value)8        i = len(self.data) - 19        while i > 0:10            parent = (i - 1) // 211            if self.data[parent] <= self.data[i]:12                break13            self.data[i], self.data[parent] = self.data[parent], self.data[i]14            i = parent15
16    def pop(self):17        # Move the last leaf to the root, then sift it down18        top = self.data[0]19        last = self.data.pop()20        if self.data:21            self.data[0] = last22            self._sift_down(0)23        return top24
25    def _sift_down(self, i):26        n = len(self.data)27        while True:28            smallest = i29            left, right = 2 * i + 1, 2 * i + 230            if left < n and self.data[left] < self.data[smallest]:31                smallest = left32            if right < n and self.data[right] < self.data[smallest]:33                smallest = right34            if smallest == i:35                return36            self.data[i], self.data[smallest] = self.data[smallest], self.data[i]37            i = smallest38
39
40heap = MinHeap()41for value in [5, 3, 8, 1, 9, 2]:42    heap.push(value)43
44print("Heap array:     ", heap.data)45print("Popped in order:", [heap.pop() for _ in range(6)])
Ejecuta este código en el Playground de Python

Preguntas frecuentes sobre heaps

¿Para qué se usa un heap?
Los heaps implementan colas de prioridad, que impulsan el algoritmo de camino más corto de Dijkstra, los planificadores de tareas y las simulaciones de eventos. También son el motor detrás de heapsort. Siempre que necesites repetidamente el elemento más pequeño o más grande de un conjunto cambiante, un heap es la herramienta.
¿Cuál es la diferencia entre un heap y un árbol binario de búsqueda?
Ambos son árboles binarios, pero un BST mantiene un orden completo de izquierda a derecha (permitiendo búsqueda ordenada), mientras que un heap solo garantiza la relación padre-hijo (mínimo o máximo en la raíz). Un heap da acceso O(1) al valor extremo; un BST da búsqueda O(log n) de cualquier valor.
¿Por qué se almacena un heap en un arreglo?
Como un heap siempre es un árbol binario completo, sus nodos se mapean perfectamente a índices de arreglo: los hijos del índice i están en 2i+1 y 2i+2, y el padre en (i-1)/2. Esto evita almacenar punteros a los hijos y ofrece un excelente rendimiento de caché.
¿Es un heap lo mismo que un arreglo ordenado?
No. Un heap solo garantiza que cada padre sea menor (min-heap) o mayor (max-heap) que sus hijos, así que los hermanos y primos no tienen ningún orden particular. Un arreglo ordenado está totalmente ordenado pero cuesta O(n) insertar en él, mientras que un heap inserta en O(log n) y sigue dando acceso instantáneo al valor extremo.
¿Cuándo debería usar un heap en vez de simplemente ordenar un arreglo?
Recurre a un heap cuando los datos cambian constantemente y solo necesitas el mínimo o el máximo actual: insertar y extraer cuestan O(log n) cada uno, frente a reordenar todo el arreglo. Si tienes un conjunto de datos estático y quieres todos los elementos en orden, una sola ordenación O(n log n) es más simple y a menudo más rápida.
¿Construir un heap con n elementos cuesta O(n log n)?
No si lo construyes de una sola vez. Insertar n elementos uno por uno es O(n log n), pero el heapify de abajo hacia arriba, que baja desde el último padre hasta la raíz, se ejecuta en O(n) en total, porque la mayoría de los nodos están cerca del fondo y bajan solo una distancia corta.
Coddy programming languages illustration

Domina los algoritmos con Coddy

COMENZAR