diff --git a/src/main/java/com/thealgorithms/datastructures/heaps/GenericHeap.java b/src/main/java/com/thealgorithms/datastructures/heaps/GenericHeap.java index f1772b5b3112..b8a289db60b9 100644 --- a/src/main/java/com/thealgorithms/datastructures/heaps/GenericHeap.java +++ b/src/main/java/com/thealgorithms/datastructures/heaps/GenericHeap.java @@ -3,49 +3,83 @@ import java.util.ArrayList; import java.util.HashMap; +/** + * A generic implementation of a max heap data structure. + * + * @param the type of elements in this heap, must extend Comparable. + */ public class GenericHeap> { - ArrayList data = new ArrayList<>(); - HashMap map = new HashMap<>(); + private final ArrayList data = new ArrayList<>(); + private final HashMap map = new HashMap<>(); + /** + * Adds an item to the heap, maintaining the heap property. + * + * @param item the item to be added + */ public void add(T item) { if (item == null) { throw new IllegalArgumentException("Cannot insert null into the heap."); } this.data.add(item); - map.put(item, this.data.size() - 1); // + map.put(item, this.data.size() - 1); upHeapify(this.data.size() - 1); } + /** + * Restores the heap property by moving the item at the given index upwards. + * + * @param ci the index of the current item + */ private void upHeapify(int ci) { int pi = (ci - 1) / 2; - if (isLarger(this.data.get(ci), this.data.get(pi)) > 0) { + if (ci > 0 && isLarger(this.data.get(ci), this.data.get(pi)) > 0) { swap(pi, ci); upHeapify(pi); } } - public void display() { - System.out.println(this.data); - } - + /** + * Returns the number of elements in the heap. + * + * @return the size of the heap + */ public int size() { return this.data.size(); } + /** + * Checks if the heap is empty. + * + * @return true if the heap is empty, false otherwise + */ public boolean isEmpty() { return this.size() == 0; } + /** + * Removes and returns the maximum item from the heap. + * + * @return the maximum item + */ public T remove() { + if (isEmpty()) { + throw new IllegalStateException("Heap is empty"); + } this.swap(0, this.size() - 1); T rv = this.data.remove(this.size() - 1); - downHeapify(0); map.remove(rv); + downHeapify(0); return rv; } + /** + * Restores the heap property by moving the item at the given index downwards. + * + * @param pi the index of the current item + */ private void downHeapify(int pi) { int lci = 2 * pi + 1; int rci = 2 * pi + 2; @@ -62,15 +96,35 @@ private void downHeapify(int pi) { } } + /** + * Retrieves the maximum item from the heap without removing it. + * + * @return the maximum item + */ public T get() { - return this.data.get(0); + if (isEmpty()) { + throw new IllegalStateException("Heap is empty"); + } + return this.data.getFirst(); } - // t has higher property then return +ve + /** + * Compares two items to determine their order. + * + * @param t the first item + * @param o the second item + * @return a positive integer if t is greater than o, negative if t is less, and zero if they are equal + */ private int isLarger(T t, T o) { return t.compareTo(o); } + /** + * Swaps two items in the heap and updates their indices in the map. + * + * @param i index of the first item + * @param j index of the second item + */ private void swap(int i, int j) { T ith = this.data.get(i); T jth = this.data.get(j); @@ -80,9 +134,16 @@ private void swap(int i, int j) { map.put(jth, i); } + /** + * Updates the priority of the specified item by restoring the heap property. + * + * @param item the item whose priority is to be updated + */ public void updatePriority(T item) { + if (!map.containsKey(item)) { + throw new IllegalArgumentException("Item not found in the heap"); + } int index = map.get(item); - // because we enter lesser value then old vale upHeapify(index); } } diff --git a/src/test/java/com/thealgorithms/datastructures/heaps/GenericHeapTest.java b/src/test/java/com/thealgorithms/datastructures/heaps/GenericHeapTest.java index 8915a6d8aef2..a3642996b769 100644 --- a/src/test/java/com/thealgorithms/datastructures/heaps/GenericHeapTest.java +++ b/src/test/java/com/thealgorithms/datastructures/heaps/GenericHeapTest.java @@ -13,114 +13,73 @@ public class GenericHeapTest { private GenericHeap heap; @BeforeEach - public void setUp() { + void setUp() { heap = new GenericHeap<>(); } @Test - public void testGenericHeapAddAndGet() { - heap.add(19); - heap.add(36); - heap.add(100); - heap.add(-17); - heap.add(3); - - // Check that the largest element (100) is at the top of the heap - assertEquals(100, heap.get()); - } - - @Test - public void testGenericHeapRemove() { - heap.add(19); - heap.add(36); - heap.add(100); - heap.add(-17); - heap.add(3); - - // Verify that the largest element is removed correctly - assertEquals(100, heap.remove()); - - // The new element at the top should be 36 - assertEquals(36, heap.get()); + void testAddAndGet() { + heap.add(10); + heap.add(20); + heap.add(5); - // Check that the size is correct after removal - assertEquals(4, heap.size()); + assertEquals(20, heap.get()); } @Test - public void testGenericHeapSize() { - assertTrue(heap.isEmpty()); - + void testRemove() { heap.add(10); heap.add(20); + heap.add(5); - // Check that the size is correct - assertEquals(2, heap.size()); - - heap.remove(); - - // After removal, the size should be 1 - assertEquals(1, heap.size()); + assertEquals(20, heap.remove()); + assertEquals(10, heap.get()); } @Test - public void testGenericHeapIsEmpty() { - // Verify that the heap is initially empty + void testIsEmpty() { assertTrue(heap.isEmpty()); - - heap.add(15); - - // Now the heap should not be empty + heap.add(1); assertFalse(heap.isEmpty()); - - heap.remove(); - - // After removing the one element, it should be empty again - assertTrue(heap.isEmpty()); } @Test - public void testGenericHeapUpdatePriority() { - heap.add(19); - heap.add(36); - heap.add(100); - heap.add(-17); - heap.add(3); - - // Verify that the largest element initially is 100 - assertEquals(100, heap.get()); + void testSize() { + assertEquals(0, heap.size()); + heap.add(1); + heap.add(2); + assertEquals(2, heap.size()); + } - heap.remove(); + @Test + void testUpdatePriority() { + heap.add(10); + heap.add(20); + heap.add(5); - // Simulates a change in priority by increasing the value of 100 to 44 - heap.add(44); + heap.updatePriority(10); + assertEquals(20, heap.get()); - // Now, the new high should be 25 - assertEquals(44, heap.get()); + heap.add(30); + heap.updatePriority(20); // 20 will be moved up + assertEquals(30, heap.get()); } @Test - public void testGenericHeapRemoveUntilEmpty() { - heap.add(5); - heap.add(3); - heap.add(4); - heap.add(1); - heap.add(2); - - // Remove all items and check that they are removed in descending order - assertEquals(5, heap.remove()); - assertEquals(4, heap.remove()); - assertEquals(3, heap.remove()); - assertEquals(2, heap.remove()); - assertEquals(1, heap.remove()); + void testRemoveFromEmptyHeap() { + Exception exception = assertThrows(IllegalStateException.class, () -> heap.remove()); + assertEquals("Heap is empty", exception.getMessage()); + } - // Empty heap - assertTrue(heap.isEmpty()); + @Test + void testGetFromEmptyHeap() { + Exception exception = assertThrows(IllegalStateException.class, () -> heap.get()); + assertEquals("Heap is empty", exception.getMessage()); } @Test - public void testGenericHeapAddNullItem() { - // Check null item - assertThrows(IllegalArgumentException.class, () -> { heap.add(null); }); + void testUpdatePriorityForNonExistentItem() { + Exception exception = assertThrows(IllegalArgumentException.class, () -> heap.updatePriority(100)); + assertEquals("Item not found in the heap", exception.getMessage()); } }