CIS 121 April 6, 2000


Examining Stacks

Today you will get a chance to examine the implementation of the methods of a Stack. Recall that we discussed the class Stack which is in the java.util package. The interface of the class is
public class Stack extends Vector {
   public Stack();

   public boolean empty();
   public Object peek();
   public Object pop();
   public Object push(Object item);
   public int search(Object o);
}
This class is implemented using Vectors. We have discussed what Vectors are. We looked at the following example of using a Stack.
import java.util.*;

public class ReversePolishNotation {
   String inputString;
   String outputString = "";

   public ReversePolishNotation(String s) {
      inputString = s;
   }

   private int priority(String s) {
      int operatorPriority = -1;

      if (s.equals("["))
         operatorPriority = 0;
      else if (s.equals("("))
         operatorPriority = 1;
      else if (s.equals("+"))
         operatorPriority = 2;
      else if (s.equals("-"))
         operatorPriority = 2;
      else if (s.equals("*"))
         operatorPriority = 3;
      else if (s.equals("/"))
         operatorPriority = 3;
      else if (s.equals("^"))
         operatorPriority = 4;

      return(operatorPriority);
   }

   private void convert() {
      Stack myStack = new Stack();
      String nextCharacter;
      String topOfStack;

      for (int i = 0;i<=inputString.length()-1;i++) {
         nextCharacter = inputString.substring(i,i+1);
         System.out.println(nextCharacter);
         if (nextCharacter.equals(")")) {
            topOfStack = (String)myStack.pop();
            while (!topOfStack.equals("(")) {
               outputString += topOfStack;
               topOfStack = (String)myStack.pop();
            }
         } else if (nextCharacter.equals("]")) {
            topOfStack = (String)myStack.pop();
            while (!topOfStack.equals("[")) {
               outputString += topOfStack;
               topOfStack = (String)myStack.pop();
            }
         } else if (nextCharacter.equals("(") ||
                    nextCharacter.equals("[")) {
            myStack.push(nextCharacter);
         } else if (nextCharacter.equals("+") ||
                    nextCharacter.equals("-") ||
                    nextCharacter.equals("*") ||
                    nextCharacter.equals("/") ||
                    nextCharacter.equals("^")) {
            topOfStack = (String)myStack.peek();
            while (priority(nextCharacter) <= priority(topOfStack)) {
               topOfStack = (String)myStack.pop();
               outputString += topOfStack;
               topOfStack = (String)myStack.peek();
            }
            myStack.push(nextCharacter);
         } else {
            outputString += nextCharacter;
         }             
      }
   }

   public String toString() {
      return(outputString);
   }

   public static void main(String[] args) {
      ReversePolishNotation myConverter = new ReversePolishNotation("[a+b]");
      myConverter.convert();
      System.out.println(myConverter);
   }
}
Download the Source Code and place it into c:\java.

When this program is compiled and executed it will produce the output of the algorithm to convert infix notation to Reverse Polish Notation. Notice that this program uses the Stack class. This is the Stack class in java.util.

Notice how this reinforces our idea of abstraction. We are using methods associated with a Stack without any knowledge of how they are implemented other than the fact that Vectors are used.

What we want to do today is replace these implementation of Stack methods with arrays.

We began discussing this yesterday in class and looked at the implementation of the non-destructive Stack methods.

public class Stack {
   final int maxSize = 100;
// Since we must declare the size of an array we establish a maximum
// size for the array for this implementation.

   Object[] myStack = new Object[maxSize];
// We now create an array of Objects. 

   Object delimiter = new String(";");
// To determine the bottom of the array we create a delimited and
// stipulate that this Stack will not be sent an Object which is
// the same as the delimiter.

   int positionOfDelimiter;
// To easily determine where the bottom entry of the stack is
// we create a integer to point to that position.

   public Stack() { // Constructor
      myStack[0] = delimiter;
// We place the delimiter at the top of the stack. In this
// implementation, the top of the stack will be position 0.

      positionOfDelimiter = 0;
// We also initialize positionOfDelimiter to point to the
// position of the delimiter.
   }

   public Object peek() { // Implementation of peek
      return(myStack[0]);
// Since the peek method is a non-destructive Stack method
// all we need to do is return the Object on top of the
// Stack and not do anything to the Stack.
   }

   public boolean empty() { // Implementation of empty
      return(myStack[0] == delimiter);
// The empty method is also a non-destructive Stack method.
// If the delimiter is at the top of the Stack, then the
// Stack is empty, so we return the result of a logical
// test.
   }

   public int search(Object o) { // Implemenation of search
      int i = 0;
// This is the last non-destructive Stack method. We use a local
// int variable to determine the position of the Object if it is
// found.

      while ((myStack[i] != o) && (i<=maxSize))
// Since i is initialized to 0, we begin searching at the top of the
// Stack. As long as the Object is not found and we have not reached
// the bottom of the Stack, we increment i.
         i++;

      return(i);
// Notice that if the Object is found, then we return the position
// in which it was found. (This was a mistake from yesterday. When
// the Object is located, the while loop will not be entered so the
// Object is in position i.) Notice that if the Object is not found
// the maxSize will be returned. We will stipulate to the calling
// environment that this indicates the Object wasn't found.
   }

   public Object pop() {


   }

   public Object push(Object item) {


   }
}
For today's lab, implement the two destructive Stack methods. Notice what has to happen in these methods.

pop

The pop method will take the top Object off the Stack and then adjust the rest of the Stack up one position. Remember to adjust the position of the delimiter.

push

The push method will adjust the entire Stack down one position and then place the Object in position 0. Remember to adjust the position of the delimiter, and remember that the return type of the method is Object.

After you have implemented these two methods, place them into the new Stack class. Make sure that the source code is in c:\java. You may download the part of the implementation we did yesterday in class.

After you implement these two methods, recompile ReversePolishNotation.java and then run it to make sure it produces the same result.