Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
5 changes: 5 additions & 0 deletions .idea/.gitignore

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 13 additions & 0 deletions .idea/compiler.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 7 additions & 0 deletions .idea/encodings.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

20 changes: 20 additions & 0 deletions .idea/jarRepositories.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 12 additions & 0 deletions .idea/misc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions .idea/vcs.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

153 changes: 153 additions & 0 deletions src/main/java/fundamentals/ResizingArrayQueue.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
package fundamentals;

import java.util.ConcurrentModificationException;
import java.util.Iterator;
import java.util.NoSuchElementException;

/**
* We are interested in the implementation of a Queue using an array.
* The array size needs to be updated when it is full or close to empty
* i.e. when the array is full, the size of the array should double
* and when the array is less than 1/4 full, the size of the array should halve.
*
* You are asked to implement this Queue by completing the class see (TODO's)
* Most important methods are:
* - the enqueue method to add an element
* - the remove method [The NoSuchElementException is thrown when the queue is empty]
Copy link

Copilot AI Dec 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment says "the remove method" but the actual method name is "dequeue". This should be corrected to reference the proper method name.

Suggested change
* - the remove method [The NoSuchElementException is thrown when the queue is empty]
* - the dequeue method [The NoSuchElementException is thrown when the queue is empty]

Copilot uses AI. Check for mistakes.
* - the iterator used to browse the queue in FIFO
*
* Hint : when the head of the stack reaches the end of the array, go back at its beginning.
Copy link

Copilot AI Dec 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment refers to "head of the stack" but this is a queue implementation, not a stack. It should say "head of the queue".

Suggested change
* Hint : when the head of the stack reaches the end of the array, go back at its beginning.
* Hint : when the head of the queue reaches the end of the array, go back at its beginning.

Copilot uses AI. Check for mistakes.
*
* @param <Item>
*/
public class ResizingArrayQueue<Item> implements Iterable<Item> {

public Item[] q;
private long nOp = 0;
// BEGIN STRIP
private int head;
private int tail;
private int size;
// END STRIP

@SuppressWarnings("unchecked")
public ResizingArrayQueue() {
q = (Item[]) new Object[2];
nOp = 0;
// BEGIN STRIP
head = 0;
tail = 0;
size = 0;
// END STRIP
}

public boolean isEmpty() {
// TODO
// Student return false;
// BEGIN STRIP
return size == 0;
// END STRIP
}

public int size() {
// TODO
// Student return 0;
// BEGIN STRIP
return size;
// END STRIP
}

private long getnOp() {
return nOp;
}
// BEGIN STRIP
@SuppressWarnings("unchecked")
private void resize(int capacity) {
nOp++;
Item[] temp = (Item[]) new Object[capacity];
for (int i = 0; i < size; i++) {
temp[i] = q[(head + i) % q.length];
}
q = temp;
head = 0;
tail = size;
}
// END STRIP

/**
* Add an item at the tail of the queue.
* Resize the array if needed.
* @param item the item to add.
*/
public void enqueue(Item item) {
// TODO
// BEGIN STRIP
nOp++;
if (size == q.length) {
resize(2 * q.length);
}
q[tail] = item;
tail = (tail + 1) % q.length;
size++;
// END STRIP
}

/**
* Removes and return the element at the head of the queue.
* Resize the array if needed.
* @return The item freshly removed.
* @throws NoSuchElementException when the queue is empty.
*/
public Item dequeue() throws NoSuchElementException{
// TODO
// STUDENT return null;
// BEGIN STRIP
nOp++;
if (isEmpty()) throw new NoSuchElementException();

Item val = q[head];
q[head] = null;
head = (head + 1) % q.length;
size--;

if (size > 0 && size == q.length / 4) {
resize(q.length / 2);
}

return val;
// END STRIP
}

/**
* Returns an iterator that iterates through the items in FIFO order.
* @return an iterator that iterates through the items in FIFO order.
*/
@Override
public Iterator<Item> iterator() {
// TODO
// STUDENT return null;
// BEGIN STRIP
return new QueueIterator();
// END STRIP
}

// BEGIN STRIP
private class QueueIterator implements Iterator<Item> {
private final long nOp = getnOp();
private int currentHead = head;

@Override
public boolean hasNext() {
return currentHead != tail;
}

@Override
public Item next() {
if (nOp != getnOp()) throw new ConcurrentModificationException();
Copy link

Copilot AI Dec 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The next() method doesn't check if there are elements remaining before accessing the array. It should call hasNext() and throw NoSuchElementException if false.

Suggested change
if (nOp != getnOp()) throw new ConcurrentModificationException();
if (nOp != getnOp()) throw new ConcurrentModificationException();
if (!hasNext()) throw new NoSuchElementException();

Copilot uses AI. Check for mistakes.
Item current = q[currentHead];
currentHead = (currentHead + 1) % q.length;
Comment on lines +138 to +148
Copy link

Copilot AI Dec 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The hasNext() implementation is incorrect. It compares currentHead != tail, but this will fail when the queue is empty (both head and tail are 0). It should also track the number of items remaining. Consider using private int remaining = size; and checking remaining > 0 in hasNext(), then decrementing it in next().

Suggested change
@Override
public boolean hasNext() {
return currentHead != tail;
}
@Override
public Item next() {
if (nOp != getnOp()) throw new ConcurrentModificationException();
Item current = q[currentHead];
currentHead = (currentHead + 1) % q.length;
private int remaining = size;
@Override
public boolean hasNext() {
return remaining > 0;
}
@Override
public Item next() {
if (nOp != getnOp()) throw new ConcurrentModificationException();
if (!hasNext()) throw new NoSuchElementException();
Item current = q[currentHead];
currentHead = (currentHead + 1) % q.length;
remaining--;

Copilot uses AI. Check for mistakes.
return current;
}
}
// END STRIP
}
122 changes: 122 additions & 0 deletions src/test/java/fundamentals/ResizingArrayQueueTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
package fundamentals;

import org.javagrader.Grade;
import org.junit.jupiter.api.Test;

import java.util.ConcurrentModificationException;
import java.util.Iterator;

import static org.junit.jupiter.api.Assertions.*;

@Grade
public class ResizingArrayQueueTest {

@Test
@Grade(value = 1, cpuTimeout = 1)
public void testBasicEnqueueDequeue() {
ResizingArrayQueue<Integer> q = new ResizingArrayQueue<>();

assertTrue(q.isEmpty());
q.enqueue(1);
q.enqueue(2);
q.enqueue(3);

assertEquals(3, q.size());
assertEquals(Integer.valueOf(1), q.dequeue());
assertEquals(Integer.valueOf(2), q.dequeue());
assertEquals(Integer.valueOf(3), q.dequeue());
assertTrue(q.isEmpty());
}

@Test
@Grade(value = 1, cpuTimeout = 1)
public void testWrapAround() {
ResizingArrayQueue<Integer> q = new ResizingArrayQueue<>();

for (int i = 0; i < 10; i++) q.enqueue(i);
for (int i = 0; i < 5; i++) assertEquals(Integer.valueOf(i), q.dequeue());
for (int i = 10; i < 15; i++) q.enqueue(i);

for (int i = 5; i < 15; i++) assertEquals(Integer.valueOf(i), q.dequeue());
assertTrue(q.isEmpty());
}

@Test
@Grade(value = 1, cpuTimeout = 1)
public void testResizeDown() {
ResizingArrayQueue<Integer> q = new ResizingArrayQueue<>();

for (int i = 0; i < 32; i++) q.enqueue(i);
Object[] arr = q.q;
int oldCap = arr.length;
assertTrue(oldCap >= 32);

while (q.size() > oldCap / 4 + 1) q.dequeue();
q.dequeue(); // should shrink here

arr = q.q;
int len = arr.length;
assertEquals(oldCap / 2, len);
}

@Test
@Grade(value = 1, cpuTimeout = 1)
public void testResizeUp() {
ResizingArrayQueue<Integer> q = new ResizingArrayQueue<>();

q.enqueue(1);
q.enqueue(2);
Object[] arr = q.q;
int len = arr.length;
assertEquals(2, len);

q.enqueue(3); // should trigger resize
arr = q.q;
len = arr.length;
assertEquals(4, len);

q.enqueue(4);
q.enqueue(5); // trigger resize again
arr = q.q;
len = arr.length;
assertEquals(8, len);
}

@Test
@Grade(value = 1, cpuTimeout = 1)
public void testIteratorOrderAndWrap() {
ResizingArrayQueue<Integer> q = new ResizingArrayQueue<>();

q.enqueue(1);
q.enqueue(2);
q.enqueue(3);
q.enqueue(4);
q.dequeue(); // head moves
q.dequeue(); // head moves
q.enqueue(5);
q.enqueue(6);

int[] expected = {3, 4, 5, 6};
int idx = 0;

for (int x : q) {
assertEquals(expected[idx++], x);
}
}

@Test
@Grade(value = 1, cpuTimeout = 1)
public void testIteratorFailFast() {
ResizingArrayQueue<Integer> q = new ResizingArrayQueue<>();
q.enqueue(1);
q.enqueue(2);
q.enqueue(3);

Iterator<Integer> it = q.iterator();
assertTrue(it.hasNext());
assertEquals(1, it.next());

q.enqueue(4); // structural modification => should break iterator
assertThrows(ConcurrentModificationException.class, it::next);
}
}