|
| 1 | +# Implementing a Heap in Java: A Comprehensive Guide |
| 2 | + |
| 3 | +A heap is a specialized tree-based data structure that satisfies the heap property. In a min heap, for any given node `i`, the value of `i` is greater than or equal to the value of its parent. This property holds true across the tree. In a max heap, the value of `i` is less than or equal to the value of its parent. |
| 4 | + |
| 5 | +In this article, we will discuss the implementation of a min heap in Java using an `ArrayList`. The heap will be able to handle generic types (`E`) that extend the `Comparable` interface. |
| 6 | + |
| 7 | +## Class Structure |
| 8 | + |
| 9 | +```java |
| 10 | +public class Heap<E extends Comparable<E>> { |
| 11 | + private List<E> list; |
| 12 | + |
| 13 | + public Heap() { |
| 14 | + list = new ArrayList<>(); |
| 15 | + } |
| 16 | +} |
| 17 | +``` |
| 18 | + |
| 19 | +In the above code, we define a class `Heap` that takes a generic parameter `E` which extends `Comparable`. This means that the elements that we add to the heap must be comparable. We use an `ArrayList` to store the elements of the heap. |
| 20 | + |
| 21 | +## Adding Elements to the Heap |
| 22 | +### Step 1: Insert 10 to heap into a Min Heap |
| 23 | + |
| 24 | + |
| 25 | + |
| 26 | +### Step 2: Insert 40 |
| 27 | + |
| 28 | + |
| 29 | + |
| 30 | +### Step 3: Insert 50 |
| 31 | + |
| 32 | + |
| 33 | + |
| 34 | +### Step 4: Insert 5 |
| 35 | + |
| 36 | + |
| 37 | + |
| 38 | +### Step 5: Swap 5 with 40 |
| 39 | + |
| 40 | + |
| 41 | + |
| 42 | +### Step 6: Swap 5 with 10 |
| 43 | + |
| 44 | + |
| 45 | + |
| 46 | + |
| 47 | + |
| 48 | + |
| 49 | + |
| 50 | + |
| 51 | + |
| 52 | + |
| 53 | +```java |
| 54 | + // Time complexity: O(log n) |
| 55 | + public void add(E e) { |
| 56 | + list.add(e); |
| 57 | + int k = list.size() - 1; |
| 58 | + // Sifting up the new element to its correct position |
| 59 | + while (k > 0 && list.get(k).compareTo(list.get(getParentIndex(k))) < 0) { |
| 60 | + swap(k, getParentIndex(k)); |
| 61 | + k = getParentIndex(k); |
| 62 | + } |
| 63 | + } |
| 64 | +``` |
| 65 | + |
| 66 | +In the `add` method, we add the element `e` to the end of the list and then sifted up the tree by comparing it to its parent and swapping places if necessary. This ensures that the heap property is maintained, where the root element is always the smallest (or largest) element in the heap. |
| 67 | + |
| 68 | +## Removing Elements from the Heap |
| 69 | + |
| 70 | +```java |
| 71 | + // Time complexity: O(log n) |
| 72 | + public E remove() { |
| 73 | + if (list.size() == 0) |
| 74 | + throw new RuntimeException("Unable to remove from an empty heap!"); |
| 75 | + |
| 76 | + E e = list.get(0); |
| 77 | + list.set(0, list.get(list.size() - 1)); |
| 78 | + list.remove(list.size() - 1); |
| 79 | + |
| 80 | + // Sifting down the element at index 0 to its correct position |
| 81 | + int parentIndex = 0; |
| 82 | + while (parentIndex < (list.size() / 2)) { |
| 83 | + int leftChildIndex = getLeftChildIndex(parentIndex); |
| 84 | + int rightChildIndex = getRightChildIndex(parentIndex); |
| 85 | + int minIndex = leftChildIndex; |
| 86 | + |
| 87 | + // Finding the smaller of the two children |
| 88 | + if (rightChildIndex < list.size() && list.get(leftChildIndex).compareTo(list.get(rightChildIndex)) > 0) { |
| 89 | + minIndex = rightChildIndex; |
| 90 | + } |
| 91 | + |
| 92 | + // Swapping the parent with the smaller child if necessary |
| 93 | + if (list.get(parentIndex).compareTo(list.get(minIndex)) > 0) { |
| 94 | + swap(parentIndex, minIndex); |
| 95 | + parentIndex = minIndex; |
| 96 | + } else { |
| 97 | + break; |
| 98 | + } |
| 99 | + } |
| 100 | + return e; |
| 101 | + } |
| 102 | +``` |
| 103 | + |
| 104 | +The `remove` method removes and returns the smallest element from the heap. It does this by swapping the first and last elements in the list, removing the last element (which is now the smallest element). The new root element is then sifted down the tree by comparing it to its children and swapping places if necessary. This ensures that the heap property is maintained. |
| 105 | + |
| 106 | +## Helper Methods |
| 107 | + |
| 108 | +The `getLeftChildIndex`, `getRightChildIndex`, and `getParentIndex` methods calculate the indices of a node's left child, right child, and parent, respectively. The `swap` method swaps the elements at two positions in the list. |
| 109 | +```java |
| 110 | + private int getLeftChildIndex(int index) { |
| 111 | + return 2 * index + 1; |
| 112 | + } |
| 113 | + |
| 114 | + private int getRightChildIndex(int index) { |
| 115 | + return 2 * index + 2; |
| 116 | + } |
| 117 | + |
| 118 | + private int getParentIndex(int index) { |
| 119 | + return (index - 1) / 2; |
| 120 | + } |
| 121 | + |
| 122 | + private void swap(int first, int second) { |
| 123 | + E firstEle = list.get(first); |
| 124 | + list.set(first, list.get(second)); |
| 125 | + list.set(second, firstEle); |
| 126 | + } |
| 127 | +``` |
| 128 | + |
| 129 | + |
| 130 | + |
| 131 | +The `isEmpty` method checks if the heap is empty, and the `size` method returns the number of elements in the heap. |
| 132 | +```java |
| 133 | + public boolean isEmpty() { |
| 134 | + return this.list.size() == 0; |
| 135 | + } |
| 136 | + |
| 137 | + public int size() { |
| 138 | + return this.list.size(); |
| 139 | + } |
| 140 | +``` |
| 141 | + |
| 142 | +With these methods, our `Heap` class is complete. We can now add elements to the heap, remove elements from the heap, and check if the heap is empty or not. This implementation of a heap is a fundamental component of many efficient algorithms and data structures. Happy coding! 🚀 |
0 commit comments