Heap

🎯 Goal: Learn what a Heap is, why it’s important, and how to implement a basic heap data structure from scratch in Java.

📝 Table of Contents

  1. Introduction to Heap
  2. Heap Properties
  3. Usage of Heap
  4. Java’s Built-in PriorityQueue
  5. Custom Heap Implementation
  6. Time and Space Complexity

1️⃣ Introduction to Heap

A Heap is a specialized tree-based data structure that satisfies the heap property. It’s essentially an array visualized as a nearly complete binary tree.


2️⃣ Heap Properties

There are mainly two types of heaps:

  • Max-Heap: In a Max-Heap, for any given node N, the value of N is greater than or equal to the values of its children.
  • Min-Heap: In a Min-Heap, for any given node N, the value of N is less than or equal to the values of its children.

Heaps are essential for algorithms that require quick access to the smallest or largest elements


3️⃣ Usage of Heap

  • Priority Queue
  • Heap Sort
  • Graph Algorithms
  • Finding Largest/Smallest elements

4️⃣ Java’s Built-in PriorityQueue

Java offers a built-in PriorityQueue class, which is essentially a min-heap.

PriorityQueue<Integer> minHeap = new PriorityQueue<>();
minHeap.add(1);
minHeap.add(2);
minHeap.add(0);
System.out.println(minHeap.poll());  // Output will be 0

5️⃣ Custom Heap Implementation

Here is a Min-Heap implementation in Java:

public class MinHeap {
    private int[] heap;
    private int size;
    private int capacity;

    public MinHeap(int capacity) {
        this.capacity = capacity;
        this.heap = new int[capacity];
        this.size = 0;
    }

    private int getParentIndex(int childIndex) {
        return (childIndex - 1) / 2;
    }

    private int getLeftChildIndex(int parentIndex) {
        return 2 * parentIndex + 1;
    }

    private int getRightChildIndex(int parentIndex) {
        return 2 * parentIndex + 2;
    }

    private boolean hasParent(int index) {
        return getParentIndex(index) >= 0;
    }

    private boolean hasLeftChild(int index) {
        return getLeftChildIndex(index) < size;
    }

    private boolean hasRightChild(int index) {
        return getRightChildIndex(index) < size;
    }

    private int parent(int index) {
        return heap[getParentIndex(index)];
    }

    private int leftChild(int index) {
        return heap[getLeftChildIndex(index)];
    }

    private int rightChild(int index) {
        return heap[getRightChildIndex(index)];
    }

    private void swap(int indexOne, int indexTwo) {
        int temp = heap[indexOne];
        heap[indexOne] = heap[indexTwo];
        heap[indexTwo] = temp;
    }

    private void ensureCapacity() {
        if (size == capacity) {
            heap = Arrays.copyOf(heap, capacity * 2);
            capacity *= 2;
        }
    }

    public int peek() {
        if (size == 0) throw new IllegalStateException();
        return heap[0];
    }

    public int poll() {
        if (size == 0) throw new IllegalStateException();
        int item = heap[0];
        heap[0] = heap[size - 1];
        size--;
        heapifyDown();
        return item;
    }

    public void add(int item) {
        ensureCapacity();
        heap[size] = item;
        size++;
        heapifyUp();
    }

    private void heapifyUp() {
        int index = size - 1;
        while (hasParent(index) && parent(index) > heap[index]) {
            swap(getParentIndex(index), index);
            index = getParentIndex(index);
        }
    }

    private void heapifyDown() {
        int index = 0;
        while (hasLeftChild(index)) {
            int smallerChildIndex = getLeftChildIndex(index);
            if (hasRightChild(index) && rightChild(index) < leftChild(index)) {
                smallerChildIndex = getRightChildIndex(index);
            }

            if (heap[index] < heap[smallerChildIndex]) {
                break;
            } else {
                swap(index, smallerChildIndex);
            }

            index = smallerChildIndex;
        }
    }

    public static void main(String[] args) {
        MinHeap minHeap = new MinHeap(10);
        minHeap.add(5);
        minHeap.add(3);
        minHeap.add(8);

        System.out.println(minHeap.peek());  // Output will be 3
        System.out.println(minHeap.poll());  // Output will be 3
        System.out.println(minHeap.peek());  // Output will be 5
    }
}

This implementation provides add, peek, and poll methods for a Min-Heap. The heapifyUp and heapifyDown methods are used to maintain the Min-Heap property when adding and removing elements. We also handle dynamic resizing of the heap with the ensureCapacity method.


6️⃣ Time and Space Complexity

  • Time Complexity: Insertion, Deletion and Extraction of min/max elements happen in O(log N).
  • Space Complexity: O(N).

Leave a Comment

Your email address will not be published. Required fields are marked *