Solution for
Programming Exercise 12.1


THIS PAGE DISCUSSES ONE POSSIBLE SOLUTION to the following exercise from this on-line Java textbook.

Exercise 12.1: In Section 12.2, I mentioned that a LinkedList can be used as a queue by using the addLast() and removeFirst() methods to enqueue and dequeue items. But, if we are going to work with queues, it's better to have a Queue class. The data for the queue could still be represented as a LinkedList, but the LinkedList object would be hidden as a private instance variable in the Queue object. Use this idea to write a generic Queue class for representing queues of Objects. Also write a generic Stack class that uses either a LinkedList or an ArrayList to store its data. (Stacks and queues were introduced in Section 11.3.)


Discussion

This is an easy exercise, but it does illustrate a few points. A queue needs enqueue, dequeue, and isEmpty methods. If the Queue class is written as indicated, then each of these methods is just one line long. For example, if queue is the variable of type LinkedList that is being used to implement the queue, then the dequeue() method is simply:

         public Object dequeue() {
            return queue.removeLast();
         }

Effectively, the three queue methods are just different names for methods that are already in the LinkedList class. So, why define the new class? The point of writing the class is not so much to make the queue methods available as to hide all the other methods from the LinkedList class. A queue is only supposed to support certain operations. It should be impossible to remove an item from the back of a queue or to add an item at the front, or to look at any item in the middle. All these things are possible for a linked list. However, in the Queue class, the linked list is a private variable and so is inaccessible from outside the class. The linked list can be accessed only indirectly, through the methods of the Queue class, and those methods allow only legitimate queue operations.

For the Stack class, you have to decide between using an ArrayList or using a LinkedList. For a queue, there is a good reason to prefer linked lists over array lists. In an array list, it's efficient to add and delete elements at the end of the list but not at the beginning. For a linked list, adding and deleting is efficient at either end. For a queue, we are forced to work at both ends since items are added at one end and are deleted at the other, so a linked list is preferable. For a stack, where items are added and deleted at the same end, we can use an array list. In fact, an array list will take up less space, since a linked list uses extra space to store pointers between nodes in the list. So, in my solution, I use an ArrayList to implement a stack

The dequeue() method given above will throw a NoSuchElementException if the queue is empty when dequeue is called. This is because queue.removeLast() throws this exception if the linked list is empty. A "NoSuchElement" exception seems OK for an empty queue. The pop operation for a stack is implemented by removing and returning the last element in an ArrayList with the command:

            return stack.remove(stack.size()-1);

If the ArrayList is empty, this will throw an IndexOutOfBoundsException. This does not seem like the right sort of exception for a stack. Arrays use indices; stacks don't. So, I wrote my pop() method to throw a different type of exception when the stack is empty:

             public Object pop() {
                   // Return and remove the top item from
                   // the stack.  Throws an EmptyStackException
                   // if there are no elements on the stack.
                if (stack.isEmpty())
                   throw new EmptyStackException();
                return stack.remove(stack.size()-1);
             }

EmptyStackException is a predefined exception class in package java.util. (In case you are wondering: Java defines this exception because it also defines a standard class java.util.Stack. This is an older class, not part of the new generic programming framework, and it is defined in terms of Vectors rather than ArrayLists.)


The Solution


  Implementing a queue as a linked list:

          import java.util.LinkedList;

          public class Queue {

             private LinkedList queue = new LinkedList();

             public void enqueue(Object obj) {
                  // Add an item to back of queue.
                queue.addLast(obj);
             }

             public Object dequeue() {
                  // Remove the next item from the front of the queue.
                  // (Note that queue.removeFirst() both removes an
                  // item from the list, and returns the item that
                  // was removed.)  Throws a NoSuchElementException
                  // if there are no items on the queue.
                return queue.removeFirst();
             }

             public boolean isEmpty() {
                  // Test if the queue is empty.
                return queue.isEmpty();
             }

          } // end class Queue


   Implementing a stack as an array list:

          import java.util.ArrayList;
          import java.util.EmptyStackException;

          public class Stack {

             private ArrayList stack = new ArrayList();

             public void push(Object obj) {
                   // Add obj to the stack.
                stack.add(obj);
             }

             public Object pop() {
                   // Return and remove the top item from
                   // the stack.  Throws an EmptyStackException
                   // if there are no elements on the stack.
                if (stack.isEmpty())
                   throw new EmptyStackException();
                return stack.remove(stack.size()-1);
             }

             public boolean isEmpty() {
                   // Test whether the stack is empty.
                return stack.isEmpty();
             }

          } // end class Stack


[ Exercises | Chapter Index | Main Index ]