diff --git a/DIRECTORY.md b/DIRECTORY.md index 2a6bf70c7632..ee1b9dcd8b11 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -833,6 +833,7 @@ * [FibonacciHeapTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/heaps/FibonacciHeapTest.java) * [GenericHeapTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/heaps/GenericHeapTest.java) * [LeftistHeapTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/heaps/LeftistHeapTest.java) + * [MinPriorityQueueTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/heaps/MinPriorityQueueTest.java) * lists * [CircleLinkedListTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/lists/CircleLinkedListTest.java) * [CountSinglyLinkedListRecursionTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/lists/CountSinglyLinkedListRecursionTest.java) diff --git a/src/main/java/com/thealgorithms/datastructures/heaps/MinPriorityQueue.java b/src/main/java/com/thealgorithms/datastructures/heaps/MinPriorityQueue.java index 9d19e9aaee1a..a1360b14dc5a 100644 --- a/src/main/java/com/thealgorithms/datastructures/heaps/MinPriorityQueue.java +++ b/src/main/java/com/thealgorithms/datastructures/heaps/MinPriorityQueue.java @@ -1,16 +1,23 @@ package com.thealgorithms.datastructures.heaps; /** - * Minimum Priority Queue It is a part of heap data structure A heap is a - * specific tree based data structure in which all the nodes of tree are in a - * specific order. that is the children are arranged in some respect of their - * parents, can either be greater or less than the parent. This makes it a min - * priority queue or max priority queue. + * A MinPriorityQueue is a specialized data structure that maintains the + * min-heap property, where the smallest element has the highest priority. * - *

+ *

In a min-priority queue, every parent node is less than or equal + * to its child nodes, which ensures that the smallest element can + * always be efficiently retrieved.

* - *

- * Functions: insert, delete, peek, isEmpty, print, heapSort, sink + *

Functions:

+ * */ public class MinPriorityQueue { @@ -18,18 +25,25 @@ public class MinPriorityQueue { private final int capacity; private int size; - // class the constructor and initializes the capacity - MinPriorityQueue(int c) { + /** + * Initializes a new MinPriorityQueue with a specified capacity. + * + * @param c the maximum number of elements the queue can hold + */ + public MinPriorityQueue(int c) { this.capacity = c; this.size = 0; this.heap = new int[c + 1]; } - // inserts the key at the end and rearranges it - // so that the binary heap is in appropriate order + /** + * Inserts a new key into the min-priority queue. + * + * @param key the value to be inserted + */ public void insert(int key) { if (this.isFull()) { - return; + throw new IllegalStateException("MinPriorityQueue is full. Cannot insert new element."); } this.heap[this.size + 1] = key; int k = this.size + 1; @@ -44,89 +58,98 @@ public void insert(int key) { this.size++; } - // returns the highest priority value + /** + * Retrieves the highest priority value (the minimum) without removing it. + * + * @return the minimum value in the queue + * @throws IllegalStateException if the queue is empty + */ public int peek() { + if (isEmpty()) { + throw new IllegalStateException("MinPriorityQueue is empty. Cannot peek."); + } return this.heap[1]; } - // returns boolean value whether the heap is empty or not + /** + * Checks whether the queue is empty. + * + * @return true if the queue is empty, false otherwise + */ public boolean isEmpty() { - return 0 == this.size; + return size == 0; } - // returns boolean value whether the heap is full or not + /** + * Checks whether the queue is full. + * + * @return true if the queue is full, false otherwise + */ public boolean isFull() { - return this.size == this.capacity; + return size == capacity; } - // prints the heap + /** + * Prints the elements of the queue. + */ public void print() { - for (int i = 1; i <= this.capacity; i++) { + for (int i = 1; i <= this.size; i++) { System.out.print(this.heap[i] + " "); } System.out.println(); } - // heap sorting can be done by performing - // delete function to the number of times of the size of the heap - // it returns reverse sort because it is a min priority queue + /** + * Sorts the elements in the queue using heap sort. + */ public void heapSort() { - for (int i = 1; i < this.capacity; i++) { + for (int i = 1; i <= this.size; i++) { this.delete(); } } - // this function reorders the heap after every delete function + /** + * Reorders the heap after a deletion to maintain the heap property. + */ private void sink() { int k = 1; - while (2 * k <= this.size || 2 * k + 1 <= this.size) { - int minIndex; - if (this.heap[2 * k] >= this.heap[k]) { - if (2 * k + 1 <= this.size && this.heap[2 * k + 1] >= this.heap[k]) { - break; - } else if (2 * k + 1 > this.size) { - break; - } + while (2 * k <= this.size) { + int minIndex = k; // Assume current index is the minimum + + if (2 * k <= this.size && this.heap[2 * k] < this.heap[minIndex]) { + minIndex = 2 * k; // Left child is smaller } - if (2 * k + 1 > this.size) { - minIndex = this.heap[2 * k] < this.heap[k] ? 2 * k : k; - } else { - if (this.heap[k] > this.heap[2 * k] || this.heap[k] > this.heap[2 * k + 1]) { - minIndex = this.heap[2 * k] < this.heap[2 * k + 1] ? 2 * k : 2 * k + 1; - } else { - minIndex = k; - } + if (2 * k + 1 <= this.size && this.heap[2 * k + 1] < this.heap[minIndex]) { + minIndex = 2 * k + 1; // Right child is smaller } + + if (minIndex == k) { + break; // No swap needed, heap property is satisfied + } + + // Swap with the smallest child int temp = this.heap[k]; this.heap[k] = this.heap[minIndex]; this.heap[minIndex] = temp; - k = minIndex; + + k = minIndex; // Move down to the smallest child } } - // deletes the highest priority value from the heap + /** + * Deletes and returns the highest priority value (the minimum) from the queue. + * + * @return the minimum value from the queue + * @throws IllegalStateException if the queue is empty + */ public int delete() { + if (isEmpty()) { + throw new IllegalStateException("MinPriorityQueue is empty. Cannot delete."); + } int min = this.heap[1]; - this.heap[1] = this.heap[this.size]; - this.heap[this.size] = min; + this.heap[1] = this.heap[this.size]; // Move last element to the root this.size--; this.sink(); return min; } - - public static void main(String[] args) { - // testing - MinPriorityQueue q = new MinPriorityQueue(8); - q.insert(5); - q.insert(2); - q.insert(4); - q.insert(1); - q.insert(7); - q.insert(6); - q.insert(3); - q.insert(8); - q.print(); // [ 1, 2, 3, 5, 7, 6, 4, 8 ] - q.heapSort(); - q.print(); // [ 8, 7, 6, 5, 4, 3, 2, 1 ] - } } diff --git a/src/test/java/com/thealgorithms/datastructures/heaps/MinPriorityQueueTest.java b/src/test/java/com/thealgorithms/datastructures/heaps/MinPriorityQueueTest.java new file mode 100644 index 000000000000..8f93bd630aa7 --- /dev/null +++ b/src/test/java/com/thealgorithms/datastructures/heaps/MinPriorityQueueTest.java @@ -0,0 +1,87 @@ +package com.thealgorithms.datastructures.heaps; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class MinPriorityQueueTest { + + @Test + void testInsertAndPeek() { + MinPriorityQueue queue = new MinPriorityQueue(5); + queue.insert(10); + queue.insert(5); + queue.insert(15); + + Assertions.assertEquals(5, queue.peek(), "The minimum element should be 5."); + } + + @Test + void testDelete() { + MinPriorityQueue queue = new MinPriorityQueue(5); + queue.insert(10); + queue.insert(5); + queue.insert(15); + + Assertions.assertEquals(5, queue.delete(), "The deleted minimum element should be 5."); + Assertions.assertEquals(10, queue.peek(), "After deletion, the new minimum should be 10."); + } + + @Test + void testIsEmpty() { + MinPriorityQueue queue = new MinPriorityQueue(5); + Assertions.assertTrue(queue.isEmpty(), "The queue should be empty initially."); + + queue.insert(10); + Assertions.assertFalse(queue.isEmpty(), "The queue should not be empty after insertion."); + } + + @Test + void testIsFull() { + MinPriorityQueue queue = new MinPriorityQueue(2); + queue.insert(10); + queue.insert(5); + + Assertions.assertTrue(queue.isFull(), "The queue should be full after inserting two elements."); + queue.delete(); + Assertions.assertFalse(queue.isFull(), "The queue should not be full after deletion."); + } + + @Test + void testHeapSort() { + MinPriorityQueue queue = new MinPriorityQueue(5); + queue.insert(10); + queue.insert(5); + queue.insert(15); + queue.insert(1); + queue.insert(3); + + // Delete all elements to sort the queue + int[] sortedArray = new int[5]; + for (int i = 0; i < 5; i++) { + sortedArray[i] = queue.delete(); + } + + Assertions.assertArrayEquals(new int[] {1, 3, 5, 10, 15}, sortedArray, "The array should be sorted in ascending order."); + } + + @Test + void testPeekEmptyQueue() { + MinPriorityQueue queue = new MinPriorityQueue(5); + Assertions.assertThrows(IllegalStateException.class, queue::peek, "Should throw an exception when peeking into an empty queue."); + } + + @Test + void testDeleteEmptyQueue() { + MinPriorityQueue queue = new MinPriorityQueue(5); + Assertions.assertThrows(IllegalStateException.class, queue::delete, "Should throw an exception when deleting from an empty queue."); + } + + @Test + void testInsertWhenFull() { + MinPriorityQueue queue = new MinPriorityQueue(2); + queue.insert(10); + queue.insert(5); + + Assertions.assertThrows(IllegalStateException.class, () -> queue.insert(15), "Should throw an exception when inserting into a full queue."); + } +}