Skip to content

refactor: Enhance docs, add tests in MinPriorityQueue #5986

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Oct 26, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions DIRECTORY.md
Original file line number Diff line number Diff line change
Expand Up @@ -832,6 +832,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)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,35 +1,49 @@
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.
*
* <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>
* Functions: insert, delete, peek, isEmpty, print, heapSort, sink
* <p>Functions:</p>
* <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 {

private final int[] heap;
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;
Expand All @@ -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 ]
}
}
Original file line number Diff line number Diff line change
@@ -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.");
}
}