refactor: Queue (#5348)

This commit is contained in:
Alex Klymenko 2024-08-19 23:03:19 +02:00 committed by GitHub
parent 04eae87512
commit 8712a7f405
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 280 additions and 184 deletions

View File

@ -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<T> {
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();
}
}

View File

@ -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]
}
}

View File

@ -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<Integer> 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));
}
}