diff --git a/src/main/java/com/thealgorithms/datastructures/queues/Queue.java b/src/main/java/com/thealgorithms/datastructures/queues/Queue.java new file mode 100644 index 00000000..046b79a0 --- /dev/null +++ b/src/main/java/com/thealgorithms/datastructures/queues/Queue.java @@ -0,0 +1,153 @@ +package com.thealgorithms.datastructures.queues; + +/** + * This class implements a Queue data structure using an array. + * A queue is a first-in-first-out (FIFO) data structure where elements are + * added to the rear and removed from the front. + * + * Note: This implementation is not thread-safe. + */ +public final class Queue { + + private static final int DEFAULT_CAPACITY = 10; + + private final int maxSize; + private final Object[] queueArray; + private int front; + private int rear; + private int nItems; + + /** + * Initializes a queue with a default capacity. + */ + public Queue() { + this(DEFAULT_CAPACITY); + } + + /** + * Constructor to initialize a queue with a specified capacity. + * + * @param capacity The initial size of the queue. + * @throws IllegalArgumentException if the capacity is less than or equal to zero. + */ + public Queue(int capacity) { + if (capacity <= 0) { + throw new IllegalArgumentException("Queue capacity must be greater than 0"); + } + this.maxSize = capacity; + this.queueArray = new Object[capacity]; + this.front = 0; + this.rear = -1; + this.nItems = 0; + } + + /** + * Inserts an element at the rear of the queue. + * + * @param element Element to be added. + * @return True if the element was added successfully, false if the queue is full. + */ + public boolean insert(T element) { + if (isFull()) { + return false; + } + rear = (rear + 1) % maxSize; + queueArray[rear] = element; + nItems++; + return true; + } + + /** + * Removes and returns the element from the front of the queue. + * + * @return The element removed from the front of the queue. + * @throws IllegalStateException if the queue is empty. + */ + @SuppressWarnings("unchecked") + public T remove() { + if (isEmpty()) { + throw new IllegalStateException("Queue is empty, cannot remove element"); + } + T removedElement = (T) queueArray[front]; + queueArray[front] = null; // Optional: Clear the reference for garbage collection + front = (front + 1) % maxSize; + nItems--; + return removedElement; + } + + /** + * Checks the element at the front of the queue without removing it. + * + * @return Element at the front of the queue. + * @throws IllegalStateException if the queue is empty. + */ + @SuppressWarnings("unchecked") + public T peekFront() { + if (isEmpty()) { + throw new IllegalStateException("Queue is empty, cannot peek front"); + } + return (T) queueArray[front]; + } + + /** + * Checks the element at the rear of the queue without removing it. + * + * @return Element at the rear of the queue. + * @throws IllegalStateException if the queue is empty. + */ + @SuppressWarnings("unchecked") + public T peekRear() { + if (isEmpty()) { + throw new IllegalStateException("Queue is empty, cannot peek rear"); + } + return (T) queueArray[rear]; + } + + /** + * Returns true if the queue is empty. + * + * @return True if the queue is empty. + */ + public boolean isEmpty() { + return nItems == 0; + } + + /** + * Returns true if the queue is full. + * + * @return True if the queue is full. + */ + public boolean isFull() { + return nItems == maxSize; + } + + /** + * Returns the number of elements currently in the queue. + * + * @return Number of elements in the queue. + */ + public int getSize() { + return nItems; + } + + /** + * Returns a string representation of the queue. + * + * @return String representation of the queue. + */ + @Override + public String toString() { + if (isEmpty()) { + return "[]"; + } + StringBuilder sb = new StringBuilder(); + sb.append("["); + for (int i = 0; i < nItems; i++) { + int index = (front + i) % maxSize; + sb.append(queueArray[index]).append(", "); + } + sb.setLength(sb.length() - 2); // Remove the last comma and space + sb.append("]"); + return sb.toString(); + } +} diff --git a/src/main/java/com/thealgorithms/datastructures/queues/Queues.java b/src/main/java/com/thealgorithms/datastructures/queues/Queues.java deleted file mode 100644 index 2f364b7c..00000000 --- a/src/main/java/com/thealgorithms/datastructures/queues/Queues.java +++ /dev/null @@ -1,184 +0,0 @@ -package com.thealgorithms.datastructures.queues; - -/** - * This implements Queues by using the class Queue. - * - * A queue data structure functions the same as a real world queue. The elements - * that are added first are the first to be removed. New elements are added to - * the back/rear of the queue. - */ -class Queue { - - /** - * Default initial capacity. - */ - private static final int DEFAULT_CAPACITY = 10; - - /** - * Max size of the queue - */ - private int maxSize; - /** - * The array representing the queue - */ - private int[] queueArray; - /** - * Front of the queue - */ - private int front; - /** - * Rear of the queue - */ - private int rear; - /** - * How many items are in the queue - */ - private int nItems; - - /** - * init with DEFAULT_CAPACITY - */ - Queue() { - this(DEFAULT_CAPACITY); - } - - /** - * Constructor - * - * @param size Size of the new queue - */ - Queue(int size) { - maxSize = size; - queueArray = new int[size]; - front = 0; - rear = -1; - nItems = 0; - } - - /** - * Inserts an element at the rear of the queue - * - * @param x element to be added - * @return True if the element was added successfully - */ - public boolean insert(int x) { - if (isFull()) { - return false; - } - // If the back of the queue is the end of the array wrap around to the front - rear = (rear + 1) % maxSize; - queueArray[rear] = x; - nItems++; - return true; - } - - /** - * Remove an element from the front of the queue - * - * @return the new front of the queue - */ - public int remove() { - if (isEmpty()) { - return -1; - } - int temp = queueArray[front]; - front = (front + 1) % maxSize; - nItems--; - return temp; - } - - /** - * Checks what's at the front of the queue - * - * @return element at the front of the queue - */ - public int peekFront() { - return queueArray[front]; - } - - /** - * Checks what's at the rear of the queue - * - * @return element at the rear of the queue - */ - public int peekRear() { - return queueArray[rear]; - } - - /** - * Returns true if the queue is empty - * - * @return true if the queue is empty - */ - public boolean isEmpty() { - return nItems == 0; - } - - /** - * Returns true if the queue is full - * - * @return true if the queue is full - */ - public boolean isFull() { - return nItems == maxSize; - } - - /** - * Returns the number of elements in the queue - * - * @return number of elements in the queue - */ - public int getSize() { - return nItems; - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("["); - for (int i = front;; i = ++i % maxSize) { - sb.append(queueArray[i]).append(", "); - if (i == rear) { - break; - } - } - sb.replace(sb.length() - 2, sb.length(), "]"); - return sb.toString(); - } -} - -/** - * This class is the example for the Queue class - * - * @author Unknown - */ -public final class Queues { - private Queues() { - } - - /** - * Main method - * - * @param args Command line arguments - */ - public static void main(String[] args) { - Queue myQueue = new Queue(4); - myQueue.insert(10); - myQueue.insert(2); - myQueue.insert(5); - myQueue.insert(3); - // [10(front), 2, 5, 3(rear)] - - System.out.println(myQueue.isFull()); // Will print true - - myQueue.remove(); // Will make 2 the new front, making 10 no longer part of the queue - // [10, 2(front), 5, 3(rear)] - - myQueue.insert(7); // Insert 7 at the rear which will get 0 index because of wrap around - // [7(rear), 2(front), 5, 3] - - System.out.println(myQueue.peekFront()); // Will print 2 - System.out.println(myQueue.peekRear()); // Will print 7 - System.out.println(myQueue); // Will print [2, 5, 3, 7] - } -} diff --git a/src/test/java/com/thealgorithms/datastructures/queues/QueueTest.java b/src/test/java/com/thealgorithms/datastructures/queues/QueueTest.java new file mode 100644 index 00000000..9a4f50d5 --- /dev/null +++ b/src/test/java/com/thealgorithms/datastructures/queues/QueueTest.java @@ -0,0 +1,127 @@ +package com.thealgorithms.datastructures.queues; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +public class QueueTest { + + private static final int INITIAL_CAPACITY = 3; + private Queue queue; + + @BeforeEach + void setUp() { + queue = new Queue<>(INITIAL_CAPACITY); + } + + @Test + void testQueueInsertion() { + Assertions.assertTrue(queue.insert(1)); + Assertions.assertTrue(queue.insert(2)); + Assertions.assertTrue(queue.insert(3)); + Assertions.assertFalse(queue.insert(4)); // Queue is full + + Assertions.assertEquals(1, queue.peekFront()); + Assertions.assertEquals(3, queue.peekRear()); + Assertions.assertEquals(3, queue.getSize()); + } + + @Test + void testQueueRemoval() { + queue.insert(1); + queue.insert(2); + queue.insert(3); + + Assertions.assertEquals(1, queue.remove()); + Assertions.assertEquals(2, queue.peekFront()); + Assertions.assertEquals(2, queue.getSize()); + + Assertions.assertEquals(2, queue.remove()); + Assertions.assertEquals(3, queue.peekFront()); + Assertions.assertEquals(1, queue.getSize()); + + Assertions.assertEquals(3, queue.remove()); + Assertions.assertTrue(queue.isEmpty()); + + Assertions.assertThrows(IllegalStateException.class, queue::remove); // Queue is empty + } + + @Test + void testPeekFrontAndRear() { + queue.insert(1); + queue.insert(2); + + Assertions.assertEquals(1, queue.peekFront()); + Assertions.assertEquals(2, queue.peekRear()); + + queue.insert(3); + Assertions.assertEquals(1, queue.peekFront()); + Assertions.assertEquals(3, queue.peekRear()); + } + + @Test + void testQueueIsEmptyAndIsFull() { + Assertions.assertTrue(queue.isEmpty()); + Assertions.assertFalse(queue.isFull()); + + queue.insert(1); + queue.insert(2); + queue.insert(3); + + Assertions.assertFalse(queue.isEmpty()); + Assertions.assertTrue(queue.isFull()); + + queue.remove(); + Assertions.assertFalse(queue.isFull()); + Assertions.assertFalse(queue.isEmpty()); + } + + @Test + void testQueueSize() { + Assertions.assertEquals(0, queue.getSize()); + queue.insert(1); + Assertions.assertEquals(1, queue.getSize()); + queue.insert(2); + Assertions.assertEquals(2, queue.getSize()); + queue.insert(3); + Assertions.assertEquals(3, queue.getSize()); + queue.remove(); + Assertions.assertEquals(2, queue.getSize()); + } + + @Test + void testQueueToString() { + Assertions.assertEquals("[]", queue.toString()); + + queue.insert(1); + queue.insert(2); + Assertions.assertEquals("[1, 2]", queue.toString()); + + queue.insert(3); + Assertions.assertEquals("[1, 2, 3]", queue.toString()); + + queue.remove(); + Assertions.assertEquals("[2, 3]", queue.toString()); + + queue.remove(); + queue.remove(); + Assertions.assertEquals("[]", queue.toString()); + } + + @Test + void testQueueThrowsExceptionOnEmptyPeek() { + Assertions.assertThrows(IllegalStateException.class, queue::peekFront); + Assertions.assertThrows(IllegalStateException.class, queue::peekRear); + } + + @Test + void testQueueThrowsExceptionOnRemoveFromEmptyQueue() { + Assertions.assertThrows(IllegalStateException.class, queue::remove); + } + + @Test + void testQueueCapacityException() { + Assertions.assertThrows(IllegalArgumentException.class, () -> new Queue<>(0)); + Assertions.assertThrows(IllegalArgumentException.class, () -> new Queue<>(-5)); + } +}