Skip to main content
Logo image

Problem Solving with Algorithms and Data Structures using Java: The Interactive Edition

Section 3.12 Implementing a Queue in Java

It is again appropriate to create a new class for the implementation of the abstract data type queue. As before, we will use the power and simplicity of the ArrayList collection to build the internal representation of the queue.
We need to decide which end of the list to use as the tail and which to use as the head. The implementation shown in Listing 3.12.1 assumes that the tail is at position 0 in the list. This allows us to use the add function on lists to add new elements to the tail of the queue. The remove operation can be used to remove the head element (the last element of the list). Recall that this also means that enqueue will be \(O(n)\) and dequeue will be \(O(1)\text{.}\)
import java.util.ArrayList;
import java.util.NoSuchElementException;

class Queue<T> {

    /*
     * The tail of the queue is at the beginning
     * of the ArrayList; the head is the last item
     */
    ArrayList<T> items;

    /*
     * Create a new Queue
     */
    public Queue() {
        this.items = new ArrayList<T>();
    }

    /*
     * Returns true if there are no items in the queue;
     * false otherwise.
     */
    public boolean isEmpty() {
        return (this.items.isEmpty());
    }

    /*
     * Add an item to the tail of the queue
     */
    public void enqueue(T item) {
        this.items.add(0, item);
    }

    /*
     * Remove the item at the head of the queue and return it.
     * If the queue is empty, throws an exception.
     */
    public T dequeue() {
        if (this.isEmpty()) {
            throw new NoSuchElementException("Queue is empty.");
        }
        return this.items.remove(this.size() - 1);
    }

    /*
     * Return the item at the head of the queue, but do not remove it.
     * If the queue is empty, throws an exception.
     */
    public T peek() {
        if (this.isEmpty()) {
            throw new NoSuchElementException("Queue is empty.");
        }
        return this.items.get(this.size() - 1);
    }

    /*
     * Returns the number of items in the queue.
     */
    public int size() {
        return this.items.size();
    }

    /*
     * Convert to string as an array from tail to head
     */
    public String toString() {

        if (!this.items.isEmpty()) {
            String arrString = this.items.toString();
            return "tail ->" + arrString + "-> head";
        } else {
            return "<<empty queue>>";
        }
    }
}
Listing 3.12.1. Implementation of a Queue
Listing 3.12.2 shows the Queue class in action as we perform the sequence of operations from Section 3.11.
Listing 3.12.2. Example Queue Operations

Exercises Self Check

1.

    Suppose you have the following series of queue operations.
    Queue<String> q = new Queue<>()
    q.enqueue("hello");
    q.enqueue("dog");
    q.enqueue("cat");
    q.dequeue();
    
    What items are left on the queue (from head to tail)?
  • "hello", "dog"
  • Remember the first thing added to the queue is the first thing removed. FIFO
  • "dog", "cat"
  • Yes, first in first out means that "hello" is gone
  • "hello", "cat"
  • Queues and stacks are both data structures where you can only access the first and the last items.
  • "hello", "dog", "cat"
  • Ooops, maybe you missed the dequeue call at the end?
You have attempted of activities on this page.