Last Section: Programmer's Tools
Last Section: Programmer's Tools
Of course, many people don't rigorously follow this top-to-bottom approach. They may, for example, take the mail off the
bottom of the stack, so as to process the oldest letter first. Or they might shuffle through the mail before they begin
processing it and put higher-priority letters on top. In these cases, their mail system is no longer a stack in the computer-
science sense of the word. If they take letters off the bottom, it's a queue; and if they prioritize it, it's a priority queue. We'll
look at these possibilities later.
////////////////////////////////////////////////////////////////
class StackX
{
private int maxSize; // size of stack array
private double[] stackArray;
private int top; // top of stack
//-------------------------------------------------------------
//-------------------------------------------------------------
//-------------------------------------------------------------
{
return stackArray[top--]; // access item, decrement top
}
//-------------------------------------------------------------
//-------------------------------------------------------------
//-------------------------------------------------------------
//-------------------------------------------------------------
////////////////////////////////////////////////////////////////
class StackApp
{
public static void main(String[] args)
{
StackX theStack = new StackX(10); // make new stack
System.out.println("");
} // end main()
} // end class StackApp
The main() method in the StackApp class creates a stack that can hold 10 items, pushes 4 items onto the stack, and then
displays all the items by popping them off the stack until it's empty. Here's the output:
80 60 40 20
Notice how the order of the data is reversed. Because the last item pushed is the first one popped; the 80 appears first in the
output.
This version of the StackX class holds data elements of type double.
StackX Class Methods
The constructor creates a new stack of a size specified in its argument. The fields of the stack comprise a variable to hold its
maximum size (the size of the array), the array itself, and a variable top, which stores the index of the item on the top of the
stack. (Note that we need to specify a stack size only because the stack is implemented using an array. If it had been
implemented using a linked list, for example, the size specification would be unnecessary. )
The push() method increments top so it points to the space just above the previous top, and stores a data item there. Notice
that top is incremented before the item is inserted.
The pop() method returns the value at top and then decrements top. This effectively removes the item from the stack; it's
inaccessible, although the value remains in the array (until another item is pushed into the cell).
The peek() method simply returns the value at top, without changing the stack.
The isEmpty() and isFull() methods return true if the stack is empty or full, respectively. The top variable is at –1 if the
stack is empty and maxSize-1 if the stack is full.
Figure 4.3 shows how the stack class methods work.
////////////////////////////////////////////////////////////////
class StackX
{
private int maxSize;
private char[] stackArray;
private int top;
//-------------------------------------------------------------
//-------------------------------------------------------------
//-------------------------------------------------------------
//-------------------------------------------------------------
//-------------------------------------------------------------
//-------------------------------------------------------------
//-------------------------------------------------------------
//-------------------------------------------------------------
output = "";
while( !theStack.isEmpty() )
{
char ch = theStack.pop(); // pop a char,
output = output + ch; // append to output
}
return output;
} // end doRev()
//-------------------------------------------------------------
-
} // end class Reverser
////////////////////////////////////////////////////////////////
class ReverseApp
{
public static void main(String[] args) throws IOException
{
String input, output;
while(true)
{
System.out.print("Enter a string: ");
System.out.flush();
// make a Reverser
Reverser theReverser = new Reverser(input);
} // end main()
//-------------------------------------------------------------
//-------------------------------------------------------------
We've created a class Reverser to handle the reversing of the input string. Its key component is the method doRev(),
which carries out the reversal, using a stack. The stack is created within doRev(), which sizes it according to the length of
the input string.
In main() we get a string from the user, create a Reverser object with this string as an argument to the constructor, call this
object's doRev() method, and display the return value, which is the reversed string. Here's some sample interaction with the
program:
Enter a string: part
Reversed: trap
Enter a string:
Queues
The word queue is British for line (the kind you wait in). In Britain, to "queue up" means to get in line. In computer science
a queue is a data structure that is similar to a stack, except that in a queue the first item inserted is the first to be removed
(FIFO), while in a stack, as we've seen, the last item inserted is the first to be removed (LIFO). A queue works like the line
at the movies: the first person to join the rear of the line is the first person to reach the front of the line and buy a ticket. The
last person to line up is the last person to buy a ticket (or—if the show is sold out—to fail to buy a ticket). Figure 4.4 shows
how this looks.
////////////////////////////////////////////////////////////////
class Queue
{
private int maxSize;
private int[] queArray;
private int front;
private int rear;
private int nItems;
//-------------------------------------------------------------
//-------------------------------------------------------------
//-------------------------------------------------------------
return temp;
}
//-------------------------------------------------------------
//-------------------------------------------------------------
//-------------------------------------------------------------
//-------------------------------------------------------------
//-------------------------------------------------------------
////////////////////////////////////////////////////////////////
class QueueApp
{
public static void main(String[] args)
{
Queue theQueue = new Queue(5); // queue holds 5 items
theQueue.insert(20);
theQueue.insert(30);
theQueue.insert(40);
System.out.println("");
} // end main()
} // end class QueueApp
We've chosen an approach in which Queue class fields include not only front and rear, but also the number of items
currently in the queue: nItems. Some queue implementations don't use this field; we'll show this alternative later.
The insert() Method
The insert() method assumes that the queue is not full. We don't show it in main(), but normally you should only call
insert() after calling isFull() and getting a return value of false. (It's usually preferable to place the check for fullness in
the insert() routine, and cause an exception to be thrown if an attempt was made to insert into a full queue.)
Normally, insertion involves incrementing rear and inserting at the cell rear now points to. However, if rear is at the top
of the array, at maxSize-1, then it must wrap around to the bottom of the array before the insertion takes place. This is done
by setting rear to – 1, so when the increment occurs rear will become 0, the bottom of the array. Finally nItems is
incremented.
The remove() Method
The remove() method assumes that the queue is not empty. You should call isEmpty() to ensure this is true before calling
remove(), or build this error-checking into remove().
Removal always starts by obtaining the value at front and then incrementing front. However, if this puts front beyond
the end of the array, it must then be wrapped around to 0. The return value is stored temporarily while this possibility is
checked. Finally, nItems is decremented.
The peek() Method
The peek() method is straightforward: it returns the value at front. Some implementations allow peeking at the rear of the
array as well; such routines are called something like peekFront() and peekRear() or just front() and rear().
The isEmpty(), isFull(), and size() Methods
The isEmpty(), isFull(), and size() methods all rely on the nItems field, respectively checking if it's 0, if it's maxSize,
or returning its value.
Deques
A deque is a double-ended queue. You can insert items at either end and delete them from either end. The methods might
be called insertLeft() and insertRight(), and removeLeft() and removeRight().
If you restrict yourself to insertLeft() and removeLeft() (or their equivalents on the right), then the deque acts like a
stack. If you restrict yourself to insertLeft() and removeRight() (or the opposite pair), then it acts like a queue.
A deque provides a more versatile data structure than either a stack or a queue, and is sometimes used in container class
libraries to serve both purposes. However, it's not used as often as stacks and queues, so we won't explore it further here.
Priority Queues
A priority queue is a more specialized data structure than a stack or a queue. However, it's a useful tool in a surprising
number of situations. Like an ordinary queue, a priority queue has a front and a rear, and items are removed from the front.
However, in a priority queue, items are ordered by key value, so that the item with the lowest key (or in some
implementations the highest key) is always at the front. Items are inserted in the proper position n to maintain the order.
Here's how the mail sorting analogy applies to a priority queue. Every time the postman hands you a letter, you insert it into
your pile of pending letters according to its priority. If it must be answered immediately (the phone company is about to
disconnect your modem line), it goes on top, while if it can wait for a leisurely answer (a letter from your Aunt Mabel), it
goes on the bottom.
When you have time to answer your mail, you start by taking the letter off the top (the front of the queue), thus ensuring
that the most important letters are answered first.
This is shown in Figure 4.10.