Assumed knowledge: before you can start this tutorial, you're supposed to have knowledge of:
- Interfaces
- Arrays
- Basic Java operations
- Exceptions
- Generics
- Basic knowledge of Object Oriented Programming (Inheritance)
This tutorial will elaborate how an array can be used in order to implement a Queue. For this purpose, we will use a custom made Queue interface and two user defined exceptions to achieve our goal. (namely a First In, First Out based queue, implemented by an array)
Before we start slamming the keyboard, we need to define what operations it needs to support. Some basic operations of a queue are:
- size, this returns an integer representing the size of the Queue
- isEmpty, this returns a boolean to denote if the Queue is empty (or not)
- enqueue, this is used to enqueue an element to the Queue (add an element to the Queue
- dequeue, this is used to dequeue an element (remove the first element)
- front, this returns (but does not remove) the first added element to the Queue
We will also define two custom exceptions for our ArrayQueue, namely:
- EmptyQueueException, thrown when elements are accessed, while the Queue is empty
- FullQueueException, thrown when an element is added, while the Queue is full
So, let's start of with defining our interface:
public interface Queue<E>{ public int size(); public boolean isEmpty(); public void enqueue(E element); public E dequeue(); public E front(); }
The next step is to define our exceptions. As these exceptions are runtime exceptions, we need to extend Javas RuntimeException class with our own exceptions. This results in:
public class FullQueueException extends RuntimeException{ public FullQueueException(String err){ super(err); } }
And:
public class EmptyQueueException extends RuntimeException{ public EmptyQueueException(String err){ super(err); } }
Of course, we could also add some basic constructors for our custom made exceptions, displaying a standard message when one of the exceptions is thrown. I leave this task up to the reader.
Now that we have defined our interface and our exceptions, we can start programming our ArrayQueue class. We will use the following variables:
- int capacity: an integer representing the capacity of our ArrayQueue
- int items: an integer representing the amount of items stored in our ArrayQueue
- int front: an integer representing where the front element is located in the array
- int rear: an integer representing where the rear element is located in the array
- E[] elements: a generic array to store the elements in the ArrayQueue
We need to consider how this should work. First, of all, consider this situation:
Assume I already enqueued (added items to the queue) and dequeued (removed items), leading to the following situation:
[][][][][][F][I]....[I]...[R]....[][][][] //F is front //I is just an item //R is rear //[] are empty spots
What happens in the queue, is that when I enqueue, I add the element at the rear [R] and when I dequeue, I remove the item at the front [F].
Now, given this situation, if I continue to enqueue, this situation might arise:
[][][][][][F][I]....[I]...[R] //F is front //I is just an item //R is rear //[] are empty spots
Now [R] is at the end of my array. If I would add two more elements, I'd get an Array Out of Bound Exception. (as the index R would be lying outside the bounds of the array) But... My array is actually not full, I can still store items in front of [F]
So, what I can do, is wrap R around the array. In that case, the positions R and F can be calculated by the modulo operator:
r = (r+1) % N
f = (f+1) % N
N being the capacity of the array holding/representing the queue.
Now we get an idea what's going on, we can (finally) start programming our ArrayQueue.
Let's start with the constructors:
ArrayQueue<E> implements Queue<E>{ int capacity; //an integer representing the capacity of our ArrayQueue int items; //an integer representing the amount of items stored in our ArrayQueue int front; //an integer representing where the front element is located in the array int rear; //an integer representing where the rear element is located in the array E elements[]; //an generic array to store the elements in the ArrayQueue //Default constructor. If this is called, an ArrayQueue with capacity 10 is instantiated public ArrayQueue(){ this.front = 0; this.rear = 0; this.capacity = 10; elements = (E[]) new Object[this.capacity]; } //Constructor to create an arrayqueue with a user defined size public ArrayQueue(int capacity){ this.front = 0; this.rear = 0; this.items = 0; this.capacity = capacity; elements = (E[]) new Object[this.capacity]; } }
So, what did we do here? We set the amount of items to 0 (as we didn't add anything), the capacity to either 10 or the user defined capacity (the amount of elements the array can store) and finally, we constructed an array based on generics.
The next step is to write the size() method and the isEmpty() method. We know that the Queue is empty when we don't have any items: thus if the variable items equals 0, then the array (and thus our Queue) is empty. This piece of code is fairly easy to implement:
//Return the amount of stored items in the ArrayQueue public int size(){ return this.items; } //Determine whether the ArrayQueue is empty public boolean isEmpty(){ return(this.items == 0); } //Determine if the ArrayQueue is full public boolean isFull(){ return(this.items == this.capacity); }
Note that I also added an isFull() method (you will see when this comes in handy)
Now, we arrive at the other operations of the ArrayQueue. Lets consider two algorithms to en- and to dequeue:
enqueue if (ArrayQueue == full) throw new FullQueueException elements[rear] = newEntry size++ rear = (rear+1) % this.capacity;
dequeue if (ArrayQueue == empty) throw new EmptyQueueException temp = elements[front]; elements[front = null; size-- front = (front+1) % this.capacity; return temp
Translating these two algorithms in Java code, results in:
//Enqueue a new item in the array queue public void enqueue(E newItem) { //Check if the ArrayQueue is full if(this.isFull()) throw new FullQueueException("Cannot enqueue, ArrayQueue is full"); //Add the element elements[rear] = newItem; items++; rear = (rear + 1) % capacity; } //Dequeue an item from the ArrayQueue public E dequeue() { //Check if the arrayQueue is empty if(this.isEmpty()) throw new EmptyQueueException("Cannot dequeue, ArrayQueue is empty"); E temp = elements[front]; elements[front] = null; items--; front = (front+1) % this.capacity; return temp; }
Only one thing remains and that's the front operation. This operation allows an user to peek at the front, but does not dequeue the element. For this program, we return a null value when the Queue is empty (you could also throw the EmptyQueue exception, but that's up to you). This results in:
//Allow the user to "look" at the first element in the queue public E front(){ return elements[front]; }
Finslly, add a toString() method to get a string representation of the ArrayQueue. Important to realize is that not only I can have null elements in the array, the array is also circularly defined. This means that I cannot loop form i = 0 till elements.length. I need to loop from the front element till the end of the array and from index i =0 to the rear. This yields in the following toString() method:
//The string representation of the ArrayQueue public String toString(){ String temp = "<ArrayQueue["; for(int i = front; i < capacity; i++) if(elements[i] != null) temp += elements[i].toString() +","; if(front == this.rear) for(int i = 0; i < this.rear; i++) if(elements[i] != null) temp += elements[i].toString() +","; if(temp.charAt(temp.length()-1) == '[') return temp + "]>"; else return temp.substring(0, temp.length()-1) + "]>"; }
Of course, you can customize the formatting of the toString method if you like

Your code for the ArrayQueue should now look like this:
Spoiler
The only thing which remains, is to test if this works. For this purpose, I used the Unit test which was generated when I did this assignment at the University (University of Technology, Delft).
Spoiler
I hope this tutorial was educational for you and I hope you can now make your own ArrayQueue, maybe with some new fancy features

Linked Lists
Level: Intermediate
Assumed knowledge: before you can start this tutorial, you are assumed to have knowledge of:
- Interfaces
- Basic Java operations
- Exceptions
- Generics
- Basic knowledge of Object Oriented Programming
Pre-requisite: A self programmed double linked list (DLL) is required. An example can be found here: http://www.dreaminco...topic273905.htm The DLL should be able to support the following operations:
- Add an element at the rear and remove an element at the front
- Retrieve the stored element at the front without removing it
- Support of generics
- A string representation
Next to the arrayqueue, a double linked list can be used to implement a First in First Out (FIFO) queue. As not everyone read the tutorial about the ArrayQueue, lets recap that part.
Before we start implementing our queue, we need to define what operations it needs to support. Some basic operations of a queue are:
- size, this returns an integer representing the size of the Queue
- isEmpty, this returns a boolean to denote if the Queue is empty (or not)
- enqueue, this is used to enqueue an element to the Queue (add an element to the Queue
- dequeue, this is used to dequeue an element (remove the first element)
- front, this returns (but does not remove) the first added element of the Queue
We will also define a custom exceptions for our Double Linked List Queue (DLLQueue), namely:
- EmptyQueueException, thrown when elements are accessed, while the Queue is empty
So, lets start of with defining our interface:
public interface Queue<E>{ public int size(); public boolean isEmpty(); public void enqueue(E newItem); public E dequeue(); public E front(); }
The next step is to define our exception called the EmptyQueueException. The name says it: when the queue is empty, this exception is thrown. As it is a runtime exception, we need to extend Javas RuntimeException class with our own exception. This results in:
public class EmptyQueueException extends RuntimeException{ public EmptyQueueException(String err){ super(err); } }
The main difference between a DLLQueue and an ArrayQueue is the dynamic nature. Because the DLLQueue has a dynamic size, we never have to worry that it gets full Therefore, we do not need a FullQueueException as we had for our ArrayQueue. However, this does come at a price as a DLLQueue will probably use more memory when compared with an ArrayQueue.
Now the interface and the exception are defined, the DLLQueue can be implemented. In order to use our DLLQueue, we need a Double Linked List which supports adding elements at the tail (addLast() operation in DLL tutorial) and removing elements at the head (removeFirst()). Furthermore, the queue should be able to retrieve an element at the front position (getFirst()), without removing it from the DLL.
Next to a variable for the DLL, we also need a variable which represents the size of the DLLQueue. In this context, the size is equal to the amount of elements. So for the DLLQueue we have two variables:
- elements, variable which denotes the double linked list for the queue
- size, variable denoting the amount of stored elements in the queue
As everything is defined, we can start to jam some code. Lets start with the constructor. As we are not bounded to a capacity, we can just instantiate an empty DLL for our DLLQueue:
public class DLLQueue<E> implements Queue<E>{ private DoubleLinkedList<E> elements; //A variable to store our DLLQueue private int size; //A variable to denote the amount of items in the DLLQueue //Default constructor, initializes an empty DLL Queue public DLLQueue(){ this.size = 0; this.elements = new DoubleLinkedList<E>(); //Instantiate an empty DLL } }
Now add two additional methods, one which returns the size of the DLLQueue and the other which determines whether the DLLQueue is empy. A Queue is empty when no elements are stored in the queue. Thus:
//Method to return the size of the Queue (Amount of stored elements) public int size(){ return size; } //Method to determine whether the Queue is empty public boolean isEmpty(){ return (size == 0); }
Note that for an ArrayQueue a circular array was used. As a result the front and the rear index has to be tracked, which was because the index has to "wrap around" the size of the Queue when elements are added and removed.
Again, we do not need to implement variables such to keep track of the index of front and rear as the DLL is dynamic. Instead, we can simply add our elements at the tail and remove them from the head. The reason for this approach is caused by the FIFO requirement, the first element in the DLL represents the first inserted element and thus should be removed when it is dequeued. The same holds for the tail: if we look at the tail, this represents the last added element, which is removed the last. Using this knowledge, we can define our remaining methods:
//Method to enqueue an item in the DLLQueue public void enqueue(E newItem){ elements.addLast(newItem); size++; //One element is added } //Method to dequeue an item from the DLLQueue public E dequeue(){ if(this.isEmpty()) //If the Queue is empty, an EmptyQueueException is thrown throw new EmptyQueueException("Cannot dequeue, the queue is empty"); else{ size--; //One element is removed return elements.removeFirst(); } } //Method to look at the front, without removing it public E front(){ if(this.isEmpty()) //If the Queue is empty, an EmptyQueueException is thrown throw new EmptyQueueException("Cannot retrieve first element, the queue is empty"); else return elements.getFirst(); }
Finally a string representation can be written. An example would be:
//The string representation of the DLL Queue //Customizable public String toString(){ return "<DLListQueue["+elements.toString()+"]>"; }
In the end, your code for the Queue should look like this:
Spoiler
This tutorial treated the implementation of the Queue by means of a DLLQueue. I hope you enjoyed this tutorial and learned something about Queues and the implementation of it by means of a (Generic) Double Linked List.

References:
Data Structures & Algorithms in Java by Michael T. Goodrich and Roberto Tamassia