mirror of
https://github.com/TheAlgorithms/Java.git
synced 2025-07-05 16:27:33 +08:00
Enhance docs, add tests in MinPriorityQueue
(#5986)
This commit is contained in:
@ -833,6 +833,7 @@
|
|||||||
* [FibonacciHeapTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/heaps/FibonacciHeapTest.java)
|
* [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)
|
* [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)
|
* [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
|
* lists
|
||||||
* [CircleLinkedListTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/lists/CircleLinkedListTest.java)
|
* [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)
|
* [CountSinglyLinkedListRecursionTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/lists/CountSinglyLinkedListRecursionTest.java)
|
||||||
|
@ -1,16 +1,23 @@
|
|||||||
package com.thealgorithms.datastructures.heaps;
|
package com.thealgorithms.datastructures.heaps;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Minimum Priority Queue It is a part of heap data structure A heap is a
|
* A MinPriorityQueue is a specialized data structure that maintains the
|
||||||
* specific tree based data structure in which all the nodes of tree are in a
|
* min-heap property, where the smallest element has the highest priority.
|
||||||
* 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.
|
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>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.</p>
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>Functions:</p>
|
||||||
* Functions: insert, delete, peek, isEmpty, print, heapSort, sink
|
* <ul>
|
||||||
|
* <li><b>insert(int key)</b>: Inserts a new key into the queue.</li>
|
||||||
|
* <li><b>delete()</b>: Removes and returns the highest priority value (the minimum).</li>
|
||||||
|
* <li><b>peek()</b>: Returns the highest priority value without removing it.</li>
|
||||||
|
* <li><b>isEmpty()</b>: Checks if the queue is empty.</li>
|
||||||
|
* <li><b>isFull()</b>: Checks if the queue is full.</li>
|
||||||
|
* <li><b>heapSort()</b>: Sorts the elements in ascending order.</li>
|
||||||
|
* <li><b>print()</b>: Prints the current elements in the queue.</li>
|
||||||
|
* </ul>
|
||||||
*/
|
*/
|
||||||
public class MinPriorityQueue {
|
public class MinPriorityQueue {
|
||||||
|
|
||||||
@ -18,18 +25,25 @@ public class MinPriorityQueue {
|
|||||||
private final int capacity;
|
private final int capacity;
|
||||||
private int size;
|
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.capacity = c;
|
||||||
this.size = 0;
|
this.size = 0;
|
||||||
this.heap = new int[c + 1];
|
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) {
|
public void insert(int key) {
|
||||||
if (this.isFull()) {
|
if (this.isFull()) {
|
||||||
return;
|
throw new IllegalStateException("MinPriorityQueue is full. Cannot insert new element.");
|
||||||
}
|
}
|
||||||
this.heap[this.size + 1] = key;
|
this.heap[this.size + 1] = key;
|
||||||
int k = this.size + 1;
|
int k = this.size + 1;
|
||||||
@ -44,89 +58,98 @@ public class MinPriorityQueue {
|
|||||||
this.size++;
|
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() {
|
public int peek() {
|
||||||
|
if (isEmpty()) {
|
||||||
|
throw new IllegalStateException("MinPriorityQueue is empty. Cannot peek.");
|
||||||
|
}
|
||||||
return this.heap[1];
|
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() {
|
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() {
|
public boolean isFull() {
|
||||||
return this.size == this.capacity;
|
return size == capacity;
|
||||||
}
|
}
|
||||||
|
|
||||||
// prints the heap
|
/**
|
||||||
|
* Prints the elements of the queue.
|
||||||
|
*/
|
||||||
public void print() {
|
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.print(this.heap[i] + " ");
|
||||||
}
|
}
|
||||||
System.out.println();
|
System.out.println();
|
||||||
}
|
}
|
||||||
|
|
||||||
// heap sorting can be done by performing
|
/**
|
||||||
// delete function to the number of times of the size of the heap
|
* Sorts the elements in the queue using heap sort.
|
||||||
// it returns reverse sort because it is a min priority queue
|
*/
|
||||||
public void heapSort() {
|
public void heapSort() {
|
||||||
for (int i = 1; i < this.capacity; i++) {
|
for (int i = 1; i <= this.size; i++) {
|
||||||
this.delete();
|
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() {
|
private void sink() {
|
||||||
int k = 1;
|
int k = 1;
|
||||||
while (2 * k <= this.size || 2 * k + 1 <= this.size) {
|
while (2 * k <= this.size) {
|
||||||
int minIndex;
|
int minIndex = k; // Assume current index is the minimum
|
||||||
if (this.heap[2 * k] >= this.heap[k]) {
|
|
||||||
if (2 * k + 1 <= this.size && this.heap[2 * k + 1] >= this.heap[k]) {
|
if (2 * k <= this.size && this.heap[2 * k] < this.heap[minIndex]) {
|
||||||
break;
|
minIndex = 2 * k; // Left child is smaller
|
||||||
} else if (2 * k + 1 > this.size) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (2 * k + 1 > this.size) {
|
if (2 * k + 1 <= this.size && this.heap[2 * k + 1] < this.heap[minIndex]) {
|
||||||
minIndex = this.heap[2 * k] < this.heap[k] ? 2 * k : k;
|
minIndex = 2 * k + 1; // Right child is smaller
|
||||||
} 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 (minIndex == k) {
|
||||||
|
break; // No swap needed, heap property is satisfied
|
||||||
|
}
|
||||||
|
|
||||||
|
// Swap with the smallest child
|
||||||
int temp = this.heap[k];
|
int temp = this.heap[k];
|
||||||
this.heap[k] = this.heap[minIndex];
|
this.heap[k] = this.heap[minIndex];
|
||||||
this.heap[minIndex] = temp;
|
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() {
|
public int delete() {
|
||||||
|
if (isEmpty()) {
|
||||||
|
throw new IllegalStateException("MinPriorityQueue is empty. Cannot delete.");
|
||||||
|
}
|
||||||
int min = this.heap[1];
|
int min = this.heap[1];
|
||||||
this.heap[1] = this.heap[this.size];
|
this.heap[1] = this.heap[this.size]; // Move last element to the root
|
||||||
this.heap[this.size] = min;
|
|
||||||
this.size--;
|
this.size--;
|
||||||
this.sink();
|
this.sink();
|
||||||
return min;
|
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 ]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -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.");
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user