E
- the type of elements held in this collectionpublic class ArrayQueue<E> extends AQueue<E> implements IQueue<E>
ArrayList
).
Can we use an ArrayList
to directly represent a queue? A FIFO needs to push on one end,
and pop from the other. The tail of an ArrayList
can support pop and push efficiently,
but the front supports neither efficiently.
Instead, we use an array for storage, and we represent the head and tail of the queue with indices into that array. When one of the indices would fall off the end of the array, it just goes back to the start of the array. That is why this pattern is called a "circular" array. Read more about that here.
We can think of the head and tail indices "chasing" each other around the circular storage. When you add an item, the tail moves. When you take an item, the head moves. If the head catches the tail, the queue is empty. If the tail catches the head, the queue is full.
That's a lot to take in, but it's easier to code than it sounds. Notice that the member variables
"removed" and "added" are counters recording the total operation count. To see where the head and
tail of the queue are, just compute:
(removed % elements.length)
or (added % elements.length)
by cspfrederick
and garethhalladay
Fall17
inspired by Chris Wilcox
Modifier and Type | Field and Description |
---|---|
protected int |
added
the total elements added (set back to zero if clear is called)
|
protected E[] |
elements
the underlying array for the queue
|
protected int |
removed
the total elements removed (set back to zero if clear is called)
|
Constructor and Description |
---|
ArrayQueue(int maxSize)
Creates a new queue backed by an array of length
maxSize . |
Modifier and Type | Method and Description |
---|---|
void |
clear()
Clears the queue.
|
boolean |
contains(java.lang.Object o)
Returns true if this queue contains the specified element.
|
static void |
main(java.lang.String[] args) |
protected E[] |
newArray(int size)
A helper method to create a new array of the generic type.
|
boolean |
offer(E e)
Adds an element to the queue.
|
E |
peek()
Returns the oldest element in the queue (the element we would remove next),
but does not remove it.
|
E |
poll()
Removes the oldest element (the head) from the queue, and returns it.
|
int |
size()
Returns the number of elements in this queue.
|
protected E[] elements
protected int added
protected int removed
public ArrayQueue(int maxSize)
maxSize
.
Use newArray(int)
to create the elements array.maxSize
- the capacity of the queuenewArray(int)
protected E[] newArray(int size)
size
- the size of the new arraypublic boolean offer(E e)
The index of the next available position can be found by calculating the remainder of the total number of elements added by the length of the array.
Don't forget to increment the added field!
public E poll()
The index of the oldest element can be determined by calculating the remainder of the total elements removed by the length of the array.
Don't forget to increment the removed field!
public E peek()
The index of the oldest element can be determined by calculating the remainder of the total elements removed by the length of the array.
public int size()
IQueue
public void clear()
Reset the count for added and removed. Also, either set all slots in the backing array to null, or reallocate a fresh array.
Why is this second step desirable? Why not just reset added and removed and call it done?
clear
in interface IQueue<E>
newArray(int)
public boolean contains(java.lang.Object o)
IQueue
public static void main(java.lang.String[] args)