Skillversitas

Heap

A Heap is a balanced binary tree that satisfies the heap property:
- Max-Heap: A parent's value is always greater than or equal to its children's values.
- Min-Heap: A parent's value is always smaller than or equal to its children's values.

Array Representation

A heap is represented as an array without pointers. For a node at index i:
- Left child: 2*i + 1
- Right child: 2*i + 2
- Parent: (i-1) // 2

# Max-Heap as an array
# Tree:     90
#          /  \
#         80   70
#        / \
#       50  60
heap = [90, 80, 70, 50, 60]

Insert (Heapify Up)

class MaxHeap:
    def __init__(self):
        self.heap = []

    def insert(self, val):
        self.heap.append(val)
        self._heapify_up(len(self.heap) - 1)

    def _heapify_up(self, i):
        parent = (i - 1) // 2
        if i > 0 and self.heap[i] > self.heap[parent]:
            self.heap[i], self.heap[parent] = self.heap[parent], self.heap[i]
            self._heapify_up(parent)

Extract (Heapify Down)

    def extract_max(self):
        if not self.heap:
            raise IndexError("Heap is empty")
        max_val = self.heap[0]
        last = self.heap.pop()
        if self.heap:
            self.heap[0] = last
            self._heapify_down(0)
        return max_val

    def _heapify_down(self, i):
        largest = i
        left = 2 * i + 1
        right = 2 * i + 2

        if left < len(self.heap) and self.heap[left] > self.heap[largest]:
            largest = left
        if right < len(self.heap) and self.heap[right] > self.heap[largest]:
            largest = right

        if largest != i:
            self.heap[i], self.heap[largest] = self.heap[largest], self.heap[i]
            self._heapify_down(largest)

Build Heap

def build_max_heap(arr):
    heap = MaxHeap()
    heap.heap = arr[:]
    for i in range(len(arr) // 2 - 1, -1, -1):
        heap._heapify_down(i)
    return heap

Python heapq (Min-Heap)

import heapq

# Min-Heap
heap = []
heapq.heappush(heap, 30)
heapq.heappush(heap, 10)
heapq.heappush(heap, 20)
print(heapq.heappop(heap))  # 10 (minimum)

# Max-Heap using negation
max_heap = []
heapq.heappush(max_heap, -30)
heapq.heappush(max_heap, -10)
print(-heapq.heappop(max_heap))  # 30 (maximum)

# Build a heap from an array
arr = [5, 3, 8, 1, 2]
heapq.heapify(arr)
print(arr)  # [1, 2, 8, 3, 5]

Time Complexity

Operation Time
Insert O(log n)
Extract O(log n)
Peek O(1)
Build Heap O(n)

Use Cases

  • Heap Sort: O(n log n) sorting.
  • Priority Queue: Access to the highest-priority element.
  • Dijkstra: Shortest path using a priority queue.
  • Streaming median: Two heaps (max + min).

Heaps are efficient for prioritization. Let's study the Priority Queue, which uses a heap as its implementation.