Introduction to Heaps


Introduction to Heaps

A heap is a specialized tree-based data structure that satisfies the heap property. In a max heap, for any given node, the value of that node is greater than or equal to the values of its children. In a min heap, for any given node, the value of that node is less than or equal to the values of its children. Heaps are commonly used to implement priority queues and for efficient sorting algorithms like heapsort.


Simple Example

Consider a max heap with the following structure:


      10
     /  \
    5    3
   / \  / \
  2  4 1  0

In this max heap, the root node has the maximum value (10), and for every node, the value of that node is greater than or equal to the values of its children.


Properties of Heaps

Heaps have several important properties:

  • Heap Property: In a max heap, the value of each node is greater than or equal to the values of its children. In a min heap, the value of each node is less than or equal to the values of its children.
  • Complete Binary Tree: Heaps are typically represented as a complete binary tree, meaning all levels are fully filled except possibly the last level, which is filled from left to right.
  • Efficient Operations: Heaps allow for efficient insertion and deletion operations, with average and worst-case time complexity of O(log n).
  • Array Representation: Heaps are often implemented using arrays, where the parent-child relationship can be easily calculated using indices.

Python Code to Implement a Heap

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

    def parent(self, i):
        return (i - 1) // 2

    def left_child(self, i):
        return 2 * i + 1

    def right_child(self, i):
        return 2 * i + 2

    def insert(self, key):
        self.heap.append(key)
        self.heapify_up(len(self.heap) - 1)

    def heapify_up(self, i):
        while i != 0 and self.heap[self.parent(i)] < self.heap[i]:
            self.heap[i], self.heap[self.parent(i)] = self.heap[self.parent(i)], self.heap[i]
            i = self.parent(i)

    def extract_max(self):
        if len(self.heap) == 0:
            return None
        root = self.heap[0]
        if len(self.heap) > 1:
            self.heap[0] = self.heap.pop()
            self.heapify_down(0)
        else:
            self.heap.pop()
        return root

    def heapify_down(self, i):
        largest = i
        left = self.left_child(i)
        right = self.right_child(i)
        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)

# Example usage:
max_heap = MaxHeap()
keys = [10, 5, 3, 2, 4, 1, 0]
for key in keys:
    max_heap.insert(key)
print("Max Heap array:", max_heap.heap)
print("Extract max:", max_heap.extract_max())
print("Heap after extraction:", max_heap.heap)

This code defines a max heap with methods for inserting nodes and extracting the maximum node, as well as maintaining the heap property through heapify operations.


Types of Heaps

There are several types of heaps, each with distinct characteristics:

  • Max Heap: A heap in which the value of each node is greater than or equal to the values of its children. The root node has the maximum value.
  • Min Heap: A heap in which the value of each node is less than or equal to the values of its children. The root node has the minimum value.
  • Binomial Heap: A heap that supports quick merging of two heaps. It is composed of binomial trees, which are a specific type of heap-ordered tree.
  • Fibonacci Heap: A heap that supports a more efficient decrease-key operation and is used in improved versions of Dijkstra's and Prim's algorithms.
  • Binary Heap: A heap represented as a binary tree, typically implemented using arrays for efficient access and manipulation.

Applications of Heaps

  • Priority Queues: Heaps are commonly used to implement priority queues, where elements are dequeued in order of their priority.
  • Heapsort: A comparison-based sorting algorithm that uses a binary heap to sort elements in O(n log n) time.
  • Graph Algorithms: Heaps are used in graph algorithms such as Dijkstra's shortest path algorithm and Prim's minimum spanning tree algorithm.
  • Order Statistics: Heaps can be used to find the kth smallest or largest element in an array.

Conclusion

Heaps are a fundamental data structure that provides efficient management of prioritized elements. Understanding their components, properties, and applications is crucial for implementing various algorithms and solving complex problems.