A heap is a specialized tree-based data structure that satisfies the heap property. It is commonly used to implement priority queues and efficient sorting algorithms like heap sort. Heaps are usually implemented as binary heaps, which means each node has at most two children.
There are two types of heaps: max heap and min heap.
Heaps are commonly implemented using arrays. The binary tree structure is represented implicitly in the array, where each node is stored at a specific index. The left child of a node at index i can be found at index (2 * i) + 1, and the right child can be found at index (2 * i) + 2. The parent of a node at index i can be found at index (i – 1) / 2.
When adding elements to a heap, the new element is inserted at the next available position and then “bubbled up” by repeatedly swapping it with its parent until the heap property is satisfied.
When removing elements from a heap, the root node is removed and replaced with the last element in the heap. Then, the new root node is “bubbled down” by comparing it with its children and swapping with the smaller child (in the case of a min-heap) or the larger child (in the case of a max heap) until the heap property is satisfied.
Heaps are efficient data structures for maintaining a partially ordered set and performing operations such as finding the maximum/minimum element or efficiently sorting elements. They are widely used in various algorithms and applications where efficient priority queue operations are required.
Code example of a min heap implementation in Java:
import java.util.Arrays;
public class MinHeap {
private int[] heap;
private int size;
private int capacity;
public MinHeap(int capacity) {
this.capacity = capacity;
this.size = 0;
this.heap = new int[capacity];
}
private int getParentIndex(int index) {
return (index - 1) / 2;
}
private int getLeftChildIndex(int index) {
return (2 * index) + 1;
}
private int getRightChildIndex(int index) {
return (2 * index) + 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 void swap(int index1, int index2) {
int temp = heap[index1];
heap[index1] = heap[index2];
heap[index2] = temp;
}
private void heapifyUp() {
int index = size - 1;
while (hasParent(index) && heap[index] < heap[getParentIndex(index)]) {
swap(index, getParentIndex(index));
index = getParentIndex(index);
}
}
private void heapifyDown() {
int index = 0;
while (hasLeftChild(index)) {
int smallerChildIndex = getLeftChildIndex(index);
if (hasRightChild(index) && heap[getRightChildIndex(index)] < heap[smallerChildIndex]) {
smallerChildIndex = getRightChildIndex(index);
}
if (heap[index] < heap[smallerChildIndex]) {
break;
} else {
swap(index, smallerChildIndex);
}
index = smallerChildIndex;
}
}
public int peek() {
if (size == 0) {
throw new IllegalStateException("Heap is empty.");
}
return heap[0];
}
public int poll() {
if (size == 0) {
throw new IllegalStateException("Heap is empty.");
}
int item = heap[0];
heap[0] = heap[size - 1];
size--;
heapifyDown();
return item;
}
public void add(int item) {
if (size == capacity) {
throw new IllegalStateException("Heap is full.");
}
heap[size] = item;
size++;
heapifyUp();
}
public boolean isEmpty() {
return size == 0;
}
public int size() {
return size;
}
@Override
public String toString() {
return Arrays.toString(Arrays.copyOfRange(heap, 0, size));
}
public static void main(String[] args) {
MinHeap minHeap = new MinHeap(10);
minHeap.add(4);
minHeap.add(2);
minHeap.add(7);
minHeap.add(1);
minHeap.add(5);
System.out.println("Heap: " + minHeap); // Output: Heap: [1, 2, 7, 4, 5]
System.out.println("Peek: " + minHeap.peek()); // Output: Peek: 1
int item = minHeap.poll();
System.out.println("Popped item: " + item); // Output: Popped item: 1
System.out.println("Heap after poll: " + minHeap); // Output: Heap after poll: [2, 4, 7, 5]
minHeap.add(0);
System.out.println("Heap after adding 0: " + minHeap); // Output: Heap after adding 0: [0, 2, 7, 5, 4]
}
}
In this example, we create a MinHeap
class with the necessary methods to implement a min-heap. We use an array to store the heap elements, and the size and capacity variables to keep track of the heap size.
The methods getParentIndex
, getLeftChildIndex
, and getRightChildIndex
are helper methods to calculate the indices of parent and child nodes based on the current index.
The methods hasParent
, hasLeftChild
, and hasRightChild
check if a node has a parent or children.
The swap
method is used to swap two elements in the heap array.
The heapifyUp
method is called after adding a new element to the heap to restore the heap property by bubbling up the element until it reaches its correct position.
The heapifyDown
method is called after removing the root element to restore the heap property by bubbling down the new root until it reaches its correct position.
The peek
method returns the minimum value in the heap without removing it.
The poll
method returns and removes the minimum value from the heap.
The add
method adds a new element to the heap while maintaining the heap property.
The isEmpty
method checks if the heap is empty.
The size
method returns the current size of the heap.
The toString
method is overridden to provide a string representation of the heap elements.
In the main
method, we create a MinHeap
object, add elements, and perform operations like peek and poll to demonstrate the functionality of the min heap implementation.
The time and space complexity of a heap data structure is as follows:
Overall, heaps provide efficient operations for maintaining a partially ordered set and performing priority queue operations. The logarithmic time complexity for the poll and add operations makes heaps suitable for scenarios where efficient retrieval of the maximum or minimum element is required.
I hope this explanation provides a comprehensive understanding of the heap data structure in data structures and algorithms.
Note: also read about DSA: Tries
If you like my post please follow me to read my latest post on programming and technology.
https://www.instagram.com/coderz.py/
https://www.facebook.com/coderz.py
Problem Statement: Given n pairs of parentheses, write a function to generate all combinations of well-formed parentheses. Example…
Given an integer A. Compute and return the square root of A. If A is…
Given a zero-based permutation nums (0-indexed), build an array ans of the same length where…
What is the Lowest Common Ancestor? In a tree, the lowest common ancestor (LCA) of…
A Binary Search Tree (BST) is a type of binary tree that satisfies the following…