-
Notifications
You must be signed in to change notification settings - Fork 21
New exercise : fundamentals - resizing array queue #22
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
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| 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] | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| * - 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. | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| * 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
AI
Dec 4, 2025
There was a problem hiding this comment.
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.
| if (nOp != getnOp()) throw new ConcurrentModificationException(); | |
| if (nOp != getnOp()) throw new ConcurrentModificationException(); | |
| if (!hasNext()) throw new NoSuchElementException(); |
Copilot
AI
Dec 4, 2025
There was a problem hiding this comment.
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().
| @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--; |
| 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); | ||
| } | ||
| } |
There was a problem hiding this comment.
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.