next up previous index
Next: Demonstration Up: Stacks Previous: Interfaces   Index


Implementation

Figure 2.3 shows the code for a class StackArray that implements the Stack interface.

Figure 2.3: A dynamic implementation of the stack.
import java.util.NoSuchElementException;

public class StackArray implements Stack {

    private Object[] stack;
    private int top; // for storing next item

    public StackArray() {
        stack = new Object[1];
        top = 0; 
    }
  
    public boolean isEmpty() {
        return top == 0;
    }
  
    public void push(Object item) {
        if (top == stack.length) {
            // expand the stack
            Object[] newStack = new Object[2 * stack.length];
            System.arraycopy(stack, 0, newStack, 0, stack.length);
            stack = newStack;
        }
        stack[top++] = item;
    }
  
    public Object pop() {
        if (top == 0) {
            throw new NoSuchElementException();
        } else {
            return stack[--top];
        }
    }
}

The principal novelty lies in the push method. This now checks first whether the current stack is full. This is indicated by the stack pointer top being positioned just beyond the bounds of the current array, i.e. by the truth of the condition (top == stack.length) so we cannot write to stack[top]. In that case we expand the stack by first creating a new array called newStack, twice the size of the current stack array. The contents of the old array are copied to the new array using
System.arraycopy(stack, 0, newStack, 0, stack.length);
This is equivalent to
for (int i = 0; i < stack.length; i++) {
    newStack[i] = stack[i];
}
but we have used the arraycopy method from the System class since it is likely to be more efficient. Finally reference to newStack is assigned to the instance variable stack. After this reassignment, the original array can no longer be addressed and it is available to the garbage collector for recovery. We can then proceed as before.

The only other novelty lies in the public constructor StackArray(). This now takes no arguments. Since we are able to expand the stack to fit the problem, there is no need for the client to specify the size. This implementation takes the smallest stack as default, namely a stack of size 1. It could be argued that there would be little use for such a small stack, and that the default should be 2, 4, 8 or whatever. That would be a fair modification, although it would involve a conventional decision about the default initial size. It would also be possible to provide another constructor taking an initial stack size as parameter; but we aim to keep things as simple as possible.

The idea of expanding the stack by a factor of two, when necessary, is sensible. It is a rough adaptation to the scale of the particular application. We want to get the size right to within an order of magnitude. You could imagine someone asking for a ball-park figure: ``are we talking tens, hundreds, thousands or what?'' Scaling up by a constant factor, $a$ say, is the simplest expression of this idea. We choose $a = 2$ but you could choose $a = 10$. For $a = 10$ there would be fewer copies needed to achieve a given stack size, but you might end up with ten times the stack size you really need. Or you might choose $a=1.5$ but this begins to appear fussy. There is no general algorithm for trading between possible waste of time and possible waste of space. The choice $a = 2$ is a reasonable compromise which is hardwired into the code here for simplicity. Note that an alternative is to add a constant amount to the current stack size, rather than multiply by a constant amount. This has the advantage of bounding the possible waste of space. But then the increment can only sensibly be specified by the user. (The current java.util implementation of the Vector class, offers the option of specifying an additive capacity increment. Otherwise, a multiplicative increment of 2 is used by default, as here.)

Note that the java.util package provides a Stack class which extends the Vector class. This also provides a peek method enabling an application to look at the object at the top of the stack without removing it from the stack, and a search method for locating an object in the stack. These would be very easy to implement. The implementation of Stack as an extension of the Vector class is at odds with the present approach, since there is no need to implement a stack in this way. It might be implemented by a linked list, for example, as we shall see below.


next up previous index
Next: Demonstration Up: Stacks Previous: Interfaces   Index
Peter Williams 2005-06-07