7. Stacks



1. Introduction

The LinkedList class that was presented in Lecture 6, provides a general mechanism implementing a dynamically adaptable structure. In Lecture 9 we will demonstrate how this basic structure can be adapted to allow

  1. Imposing a particular ordering dependent on the data held in the Datum field of the ListCells, e.g. if these were always instances of type String it might be desirable for successive Datum fields to be alphabetically ordered.
  2. Insertion of a new ListCell at any position in the LinkedList.
  3. Deletion of any ListCell.
  4. Ensuring that the Datum held in each ListCell is distinct.

There are many applications, however, for which it is useful to impose a strict regime governing the order in which data held in a structure can be accessed. Examples of such regimes are:

Notice that the form prescribed by the LIFO regime, has been realised by the LinkedList class. There are, however, many other mechanisms which could have been used to the same effect.

The ADTs used to hold data so that access to these is controlled by the different protocols described have specific names associated with them in a Computer Science context.

Several of you will already have met Stack structures in the context of low-level programming on the module COMP103.

In this lecture we consider the standard set of operations associated with Stacks, examine their realisation in Java, and analyse an example application using them. Queue structures will be considered in the next lecture.

2. Stacks

The Stack ADT is a frequently used structure particularly within the realisation of systems software programs, e.g. High-level language compilers and Operating Systems. Typical applications of Stacks in the former instance are:

  1. In compilers for imperative languages that support recursive methods (procedures), Stacks provide a mechanism for resolving references to local parameters (and variables) over successive recursive calls, e.g. if we consider the method below to calculate the value of n!

    
    public static int factorial ( final int n )
      {
      if (n==1)
        return 1;
      else
        return n*factorial(n-1);
      }
    

    The parameter n referenced when this method is called is `different' on successive recursive calls. The usual technique that is employed in compilers in order to `keep track' of the `correct' reference, is to place (push) the (reference to) the `new' location of n for a given recursive call onto a stack. This can be emptied (or popped) once the terminating condition (n==1) has been reached.

  2. In order to evaluate arithmetic expressions, many compilers first transform these into a notation known as Postfix or Reverse Polish Notation (in honour of the Polish logician Jan Lukasiewicz who propounded the notational system of which this is a variant). The advantage of this is that no parentheses to delimit sub-expressions are required: the only items occurring in a Reverse Polish Expression are operator symbols (+, -, *, /, etc.) and operands (variables and constants). Using a Stack provides a simple algorithm for processing and evaluating arithmetic expressions represented in Postfix notation.

Figure 7.1, below presents a Java Class Diagram for a Stack Object. In naming the methods used, we have adhered to the conventional names by which these are usually referred in the literature and applications programs.

Figure 7.1: Class Diagram for a Stack Object.

Notice there is a similarity to the ListCell class that we considered in Lecture 5: the fields of a Stack instance are:

The first two of these play a role similar to that of the fields Datum and Link defined for the ListCell class.

Of the two constructors, only one of these

public Stack()

is available for use by applications employing the Stack class. The other one,

private Stack(Object, Stack)

is only available to be used internally within Instance methods of the class. The implementation of this constructor is, again, similar to the corresponding constructor within the ListCell class.

By using 2 constructors, one of which is hidden, we save nesting the ListCell class details within the Stack class realisation, while continuing to avoid the drawbacks that led to this being done for our LinkedList realisation of Lecture 6.

Of the 5 instance methods, the important operations on a Stack are

  1. public boolean IsEmptyStack()

    which returns true if and only if this Stack contains no data Objects.

  2. public void Push(Object T)

    which places a new Object, T, onto the top of this Stack.

  3. public void Pop()

    which removes the Object at the top of this Stack.

  4. public Object Peek()

    which returns the Object at the top of this Stack, but without altering the Stack contents.

The full implementation of the Stack class is given in Figure 7.2., below


//
// COMP102
// Example 10: Stacks
//            
//
// Paul E. Dunne 11/11/99
//
public class Stack
  {
  //******************************************************
  // Stack Fields                                        *
  //******************************************************
  private Object Top;         
  private Stack Rest;         
  private int CellCount;
  //******************************************************
  // Stack Constructors                                  *
  //******************************************************
  public Stack()
    {
    Top  = null;
    Rest = null;      
    CellCount=0; // Initiates the empty Stack
    }
  //***************************************************************
  // This constructor is private, and is used to ensure that      *
  // the correct sequence of pointers is set up for this instance *
  //***************************************************************
  private Stack( Object Item, Stack rest_of )
     {
     Top = Item;
     Rest = rest_of;
     }
     
  //******************************************************
  // Stack Instance Methods                              *
  //******************************************************
  //
  //  Test if this instance is the Empty Stack.
  //
  public boolean IsEmptyStack()
    {
    return (CellCount==0); 
    };
  //
  //************************************************************
  //  Add a new Cell as the first cell in this Stack           *
  //************************************************************
  //
  public void Push ( Object Datum )
    {
     if (IsEmptyStack())
       {
       Top =Datum;
       Rest = null;
       }
     else
       {
       Rest = new Stack (Top,Rest);  // N.B. Use of private Constructor here; 
                                     // compare with ListCell Constructor earlier.
       Top = Datum;
       };
     this.CellCount++;
    }
  //
  //************************************************************************
  //  Remove the Cell at the top of this Stack.                            *
  //  i.e. if the current Stack is [Top]::[Rest], the `new' one is [Rest]. *
  //************************************************************************
  //
  public void Pop()
    {
    if (CellCount<=1)           // There is an argument for raising
      {                         // an exception if CellCount=0
                                // however, we adopt the convention
                                // that Pop() applied to
                                // the empty Stack leaves the empty Stack.
      Top = null; 
      Rest=null;

      CellCount=0;
      }
    else
      {
      Top = Rest.Top;
      CellCount--;             // and this Stack has one fewer cell.
      if (CellCount==1)
        Rest=null;             // If there's only a single cell then its Rest field
                               // must point to the empty Stack (i.e. null reference)
      else
        Rest = Rest.Rest;      // Otherwise we can update Rest without any problem.
      };
    }
  //
  //**********************************************************************
  //  Obtain the Object in the Top field of this Stack                   *
  //  This method will not change the current instantiation.             *
  //**********************************************************************
  //
  public Object Peek()
    {
    if (!(CellCount==0))                // If there's anything to return
      return this.Top;                // then return it.
    else
      return null;                      // otherwise return a null reference.
    }
  //
  //******************************************************
  // Convert this Stack to a String suitable for output. *
  //******************************************************
  //
  public String toString()
    {
    String res = new String();
    Stack temporary = new Stack();
    temporary.Top = this.Top; 
    temporary.Rest = this.Rest; 
    temporary.CellCount=this.CellCount;
    while (!temporary.IsEmptyStack())
      {
      res = res+(temporary.Peek()).toString()+"\n";
      temporary.Pop();
      };
    return res;
    }     
  }

Figure 7.2: Implementation of a Stack Class in Java

2.1. An Example Application Using The Stack Class: Evaluation of Reverse Polish Expressions

Earlier we mentioned a standard application of Stacks, arising in the context of High-level Language Compilers, was to generate appropriate low-level code to evaluate an arithmetic expression given in the form of Reverse Polish Notation (RPN) (also called, for reasons that will become obvious, Postfix Notation).

As an example of using the Stack class, we develop a Java program that will take as input an arithmetic expression in RPN (involving non-negative integer constants and the arithmetic operations +, -, *, /) and output the integer value to which this expression corresponds.

Before giving a more complete description of the requirements, we first give a precise definition of what constitutes an Integer valued Reverse Polish expression.

An Integer value arithmetic expression, E is in Reverse Polish Form if:

  1. E consists of a single integer constant.

    OR

  2. E has the form:

    E1 E2 < operation >

    where E1 and E2 are both integer valued arithmetic expressions in Reverse Polish Form, and < operation > is one of +, -, *, /.

If E is an integer arithmetic expression in Reverse Polish Form, its arithmetic value, V(E), is

  1. The integer constant comprising E, if its form is as in (1).
  2. The value of,

    V(E1) < operation > V(E2)

    if its form is as in (2).

Reverse Polish Form for Integer Arithmetic Expressions

For example, the following are all expressions in Reverse Polish Form:

ExampleExpressionForm (1) or (2)Value
125(1), Constant25
20 5 -(2) E1=0; E2=5; opn=--5 = 0-5
325 0 5 - /(2) E1=(Ex1); E2=(Ex2); opn=/ -5 = V( Ex1 )/V(Ex2)
425 0 5 - / 10 +(2) E1=(Ex3); E2=10; opn=+5 = V(Ex3) + 10

Figure 7.3 Some Simple Examples of Reverse Polish Notation and their Evaluation.

We can now give a fuller description of the,

Requirements

Given a sequence, S, of input data comprising non-negative integer values and arithmetic operations, terminated by the character @, print out the integer value V(S) if S is a correctly formed integer arithmetic expression in Reverse Polish Notation; if S is not a correctly formed expression in Reverse Polish Notation output an error message.

It may be assumed that all constant values occurring in S are non-negative integers (i.e. there are no floating point values).

Analysis

  1. Reverse Polish Notation Evaluation Algorithm

    Consider the recursive definition given earlier of the value of an expression in Reverse Polish. This definition indicates that the value of

    E1 E2 < operation >

    could be found be finding the operation at the end of the expression, (this would be the symbol preceding the @ sign in the requirements description) and then applying this to the value of the two preceding expressions. With a typical input S, however, being a sequence of integer values and operators, how do we find out where E1 ends? The answer is that it is not necessary to know this. All we have to notice is that any well-formed RPN (if it's not a constant value) must end with an operator symbol. So consider the following `informal' algorithm for processing S:

    Suppose

    S = w1 w2 ... wk ... wm

    where each wi is either an integer constant or an operator symbol:

    1.i=1
    2.if wi is an integer constant
    then `save' its value `somewhere'
    3.if wi is an operator
    then `replace' the `last' value saved with
    the result of applying the operator to the
    'last' two values saved.
    4.i = i+1
    5.Go to Step 2. if i<=m

    Thus this approach performs a calculation every time an operator is found in the input data. Furthermore, the operation is carried out on the two most recently saved constant values. In other words, the ordering regime is such that the last integer constant `saved' will be the first one to be used when an operator is found.

    This suggests realising steps (2) and (3) by using a stack as the structure on which to `save' values.

  2. Implementing the Algorithm

    The fields required in the main() method, are given with a description below:

    
    Stack RPN_Expr;                  // The expression being evaluated.
    Integer Operand= new Integer(0); // Object sub-class to use when
                                     // placing integer values on Stack.
                                     // N.B. Wrapper class.
    int ValueLeft,ValueRight;        // Used during evaluation of expression in
                                     // the form Left Right <opn>, so that
                                     // ValueLeft == V(Left); 
                                     // ValueRight == V(Right);
    int FinalValue=0;            // For the expression result.
    String temp;                 // Will hold integer values under construction
    

    The natural control mechanism structure suggested by the requirements is that of a while loop, during the running of which input data is read and processed, i.e.

    
    while ( termination symbol not read && no errors found in expression )
      {
      Continue processing input data
      };
    

    Since there are several different ways in which a badly-formed Reverse Polish Expression could arise, we use a boolean `flag' which is set to true when an error is discovered.

    In addition, since a single character ('@') is used to indicate the end of an expression, the natural input mechanism is to read data one character at a time from the input stream. So we will add the following variables to those in the main() method.

    • char next_ch;
    • boolean error_flag = false; // Set to true if invalid expression detected.

    So that the loop condition becomes,

    
    while ( !( (next_ch=='@')||(error_flag) ))
      {
      Continue processing input data
      };
    

    1. Processing Input Data

      The input (from a keyboard or prepared file) characters can be classified into 5 distinct groups:

      1. Digits, i.e. characters from the set {'0','1','2','3','4','5','6','7','8','9'}.
      2. Arithmetic operator symbols, i.e. from the set {'+','-','*','/'}
      3. So-called "white space", e.g. literal spaces, tab characters, line breaks, etc.
      4. The `end of expression' symbol, i.e. the character '@'.
      5. Anything not belonging to one of the first 4 groups above.

      Any input character in the last group cannot be part of a well-formed expression, so if such are detected the error_flag can be set to true. The action required when the termination symbol is read has already been described. What about the remaining character groups?

      Obviously, we want to ignore any characters that belong to the `white space' category, and so arrange that the next_ch variable will only result in one of the other four categories requiring action to be taken in processing the expression. In order to facilitate this, the method in Figure 7.4 is used.

      
      //*******************************************************
      // Strip out spaces and newlines between input items    *
      // Return the first `non white space' char found.       *
      //*******************************************************
      public static char IgnoreWhiteSpace( BufferedReader instream) 
                                          throws IOException
        {
        char c=' ';
        while (Character.isWhitespace(c))
          {
          c = (char)instream.read();
          };
        return c;
        }
      

      Figure 7.4: Method to return the next non `white space' char in the input.

      This is invoked to set the initial value of next_ch prior to the main while loop being entered.

      This leaves us with the first two groups which are the cases that one would expect to predominate in a typical input.

      In order to recognise whether the character in next_ch is one of the operator symbols, we can use a method that performs a simple test on a character parameter, i.e

      
      //***************************************************************
      //  Check if the character just read is an arithmetic operation *
      //***************************************************************
      public static boolean OperatorSymbol( char c )
        {
        return ( (c=='+')||(c=='-')||(c=='*')||(c=='/') );
        }
      

      Of course there are further actions required in this case (as there are if we find that the character is a digit).

    2. Processing after character group determined

      The framework we have so far is:

      
      next_ch = IgnoreWhiteSpace(keyboardInput);   // Find first 
                                                   // `real' input char.
      while (!( (next_ch=='@')||(error_flag) ))
         {
         if Character.IsDigit (next_ch)
           Process digit case
         else if OperatorSymbol(next_ch)
           Process Operator case
         else
           error_flag = true
         }
         ...
      

      Process Digit Case

      A digit indicates that item to be read is an integer constant value. In this case it is necessary to

      1. Read the remaining digits (if any) in this integer.
      2. `Wrap' the value read as an Integer.
      3. Place this Integer onto the RPN_Expr Stack
      4. Ensure that the next_ch value is not a `white space' character.
      That is,

      
      temp = new String();
      //
      //********************************************
      // If next item is an integer value;         *
      // then it will start with a digit.          *
      //********************************************
      //
      if (Character.isDigit(next_ch))
        {
        //*************************************************
        // and end at the character immediately preceding *
        // the next non-digit character read.             *
        //*************************************************
        while (Character.isDigit(next_ch))   
          {
          temp = temp+next_ch;
          next_ch = (char)keyboardInput.read();
          };
        Operand = new Integer(temp);
        RPN_Expr.Push(Operand);  // Put the value just read onto the Stack.
        //********************************************************************
        // The non-digit character might be a space, or linebreak            *
        // If it is, we want the next character inspected to be a digit      *
        // or operation and so we have to get rid of intermediate 'noise'    *
        // characters (spaces, linebreaks, etc.).                            *
        //********************************************************************
        if (Character.isWhitespace(next_ch))
          next_ch = IgnoreWhiteSpace(keyboardInput);
        }
      

      Figure 7.5 Realisation of the steps required when next_ch is a digit.

      Process Operator Symbol Case

      Following the algorithm outlined earlier when next_ch indicates an operator symbol, the following action is required

      1. Obtain the integer at the top of the stack: this will be V(E2).
      2. Remove this value from the stack.
      3. Obtain the integer now at the top of the stack: this will be V(E1).
      4. Remove this value from the stack.
      5. Calculate the result of
        V(E1)<opn>V(E2)
      6. Save the value just computed onto the Stack.

      If there are fewer than two items on the RPN_Expr Stack then it must be the case that the expression was not properly formed RPN, in which event the error_flag can be set.

      
      //********************************************************************
      // If the character is an operator then the top 2 items              *
      // currently on the Stack, (V1, V2 say) can be replaced by           *
      // the integer value V1 <op> V2.                                     *
      //********************************************************************
      else if (OperatorSymbol(next_ch))
        {
        //*****************************************************************
        // If the input expression is in a correct form then there        *
        // must be (at least) 2 values on the Stack at this point.        *
        //*****************************************************************
        if (RPN_Expr.IsEmptyStack())
          error_flag = true;
        else
          {
          //*************************************************
          // Find out the value of the `right-hand' operand.*
          //*************************************************
          ValueRight = (Integer.valueOf(RPN_Expr.Peek().toString())).intValue();
          RPN_Expr.Pop();      // and remove it from the Stack.
          //********************************************************************
          // Make sure that there's at least one value remaining on the Stack. *
          //********************************************************************
          if (RPN_Expr.IsEmptyStack())
            error_flag=true;
          else
            {
            //*************************************************
            // Find out the value of the `left-hand' operand. *
            //*************************************************
            ValueLeft = (Integer.valueOf(RPN_Expr.Peek().toString())).intValue();
            RPN_Expr.Pop();      // and remove this from the Stack,
            switch (next_ch)     // Now compute what should replace these values.
              {
              case '+': Operand = new Integer(ValueLeft+ValueRight);
                        break;
              case '-': Operand = new Integer(ValueLeft-ValueRight);
                        break;
              case '*': Operand = new Integer(ValueLeft*ValueRight);
                        break;
              case '/': Operand = new Integer(ValueLeft/ValueRight);
              };
            RPN_Expr.Push(Operand);   // and save it onto the Stack.
            next_ch = IgnoreWhiteSpace(keyboardInput); // Continue with the
                                                       // next character.
            };
          };
        }
      

      Figure 7.6: Stack Processing when Operator Symbol Occurs.

    The final stage is to output the value remaining on the RPN_Expr Stack when the loop is exited, checking that exactly one value remains on the Stack.

    The full realisation of the algorithm is given in Figure 7.7.


    
    //
    // COMP102
    // Example 11: Evaluation of Arithmetic Expressions
    //             in Reverse Polish Notation Using
    //             the Stack class.
    //
    // Paul E. Dunne 15/11/99
    //
    import java.io.*;
    import Stack;
    public class RPN
      {
      public static InputStreamReader input = new InputStreamReader(System.in);
      public static BufferedReader   keyboardInput = new BufferedReader(input);
      //*******************************************************
      // Strip out spaces and newlines between input items    *
      // Return the first `non white space' char found.       *
      //*******************************************************
      public static char IgnoreWhiteSpace( BufferedReader instream) 
                                          throws IOException
        {
        char c=' ';
        while (Character.isWhitespace(c))
          {
          c = (char)instream.read();
          };
        return c;
        }
      //***************************************************************
      //  Check if the character just read is an arithmetic operation *
      //***************************************************************
      public static boolean OperatorSymbol( char c )
        {
        return ( (c=='+')||(c=='-')||(c=='*')||(c=='/') );
        }
      //***************************************************************
      //                   Main method                                *
      //***************************************************************
      public static void main( String[] args) throws IOException
        {
        Stack RPN_Expr;                  // The expression being evaluated.
        Integer Operand= new Integer(0); // Object sub-class to use when
                                         // placing integer values on Stack.
                                         // N.B. Wrapper class.
        int ValueLeft,ValueRight;        // Used during evaluation of expression
                                         // in the form Left Right <opn>,
                                         // so that ValueLeft == V(Left); 
                                         // ValueRight == V(Right);
        int FinalValue=0;            // For the expression result.
        char next_ch;                // Characters read from input stream.
        boolean error_flag = false;  // Set to true if invalid expression.
        String temp;                 // Will hold integer values.
        String Clearout;             // Remove anything left on input line,
                                     // before prompting for continuation.
        char YesNo='N';              // To indicate whether to continue.
        //***********************************************************************
        System.out.println("Enter arithmetic expression in Reverse Polish Form");
        System.out.println("use '@' symbol to end expression");
        next_ch = IgnoreWhiteSpace(keyboardInput);   // Find first `real' input.
        RPN_Expr = new Stack();
        //
        //***************************************************************
        // Continue evaluation until end of expression marker reached   *
        // or an error has been found in the expression input form.     *
        //***************************************************************
        //
        while (!( (next_ch=='@')||(error_flag) ))
          {
          temp = new String();
          //
          //********************************************
          // If next item is an integer value;         *
          // then it will start with a digit.          *
          //********************************************
          //
          if (Character.isDigit(next_ch))
            {
            //*************************************************
            // and end at the character immediately preceding *
            // the next non-digit character read.             *
            //*************************************************
            while (Character.isDigit(next_ch))   
              {
              temp = temp+next_ch;
              next_ch = (char)keyboardInput.read();
              };
            Operand = new Integer(temp);
            RPN_Expr.Push(Operand); // Put the value just read onto the Stack.
            //********************************************************************
            // The non-digit character might be a space, or linebreak            *
            // If it is, we want the next character inspected to be a digit      *
            // or operation and so we have to get rid of intermediate 'noise'    *
            // characters (spaces, linebreaks, etc.).                            *
            //********************************************************************
            if (Character.isWhitespace(next_ch))
              next_ch = IgnoreWhiteSpace(keyboardInput);
            }
          //********************************************************************
          // next_ch cannot be a whitespace character. If it's not a digit     *
          // it should be an operator symbol (or the terminal '@' symbol).     *
          //********************************************************************
          // If the character is an operator then the top 2 items              *
          // currently on the Stack, (V1, V2 say) can be replaced by           *
          // the integer value V1 <op> V2.                                     *
          //********************************************************************
          else if (OperatorSymbol(next_ch))
            {
            //*****************************************************************
            // If the input expression is in a correct form then there        *
            // must be (at least) 2 values on the Stack at this point.        *
            //*****************************************************************
            if (RPN_Expr.IsEmptyStack())
              error_flag = true;
            else
              {
              //*************************************************
              // Find out the value of the `right-hand' operand.*
              //*************************************************
              ValueRight = 
                 (Integer.valueOf(RPN_Expr.Peek().toString())).intValue();
              RPN_Expr.Pop();      // and remove it from the Stack.
              //***************************************************************
              // Make sure there's at least one value remaining on the Stack. *
              //***************************************************************
              if (RPN_Expr.IsEmptyStack())
                error_flag=true;
              else
                {
                //*************************************************
                // Find out the value of the `left-hand' operand. *
                //*************************************************
                ValueLeft = 
                   (Integer.valueOf(RPN_Expr.Peek().toString())).intValue();
                RPN_Expr.Pop();      // and remove this from the Stack,
                switch (next_ch)     // Compute what should replace these.
                  {
                  case '+': Operand = new Integer(ValueLeft+ValueRight);
                            break;
                  case '-': Operand = new Integer(ValueLeft-ValueRight);
                            break;
                  case '*': Operand = new Integer(ValueLeft*ValueRight);
                            break;
                  case '/': Operand = new Integer(ValueLeft/ValueRight);
                  };
                RPN_Expr.Push(Operand);   // and save it onto the Stack.
                next_ch = IgnoreWhiteSpace(keyboardInput); // Continue with the
                                                           // next character.
                };
              };
            }
          //**************************************************************
          // The character read cannot be the terminating '@' symbol so  *
          // if it was not a digit, and not an operator symbol, then the *
          // input expression is not in correct RPN.                     *
          // In this case, we can set the error flag to true and exit.   *
          //**************************************************************
          else
            error_flag = true;
          };
          //*******************************************************
          // On completion, there should be exactly one value on  *
          // the Stack.                                           *
          //*******************************************************
          if (RPN_Expr.IsEmptyStack())
            error_flag=true;
          else
            {
            FinalValue = 
                    (Integer.valueOf(RPN_Expr.Peek().toString())).intValue();
            RPN_Expr.Pop();
            };
          //***********************************
          // Now the Stack should be empty.   *
          //***********************************
          if (!(RPN_Expr.IsEmptyStack()))
            error_flag=true;
          //
          if (error_flag)
            System.out.println
                ("Expression is not in correct Reverse Polish Notation");
          else
            System.out.println("The value of this expression is "+ FinalValue);
          System.out.println();
          Clearout = keyboardInput.readLine();   // Get rid of any noise.
          System.out.print("Continue with another expression? (Y/y):");
          YesNo = (keyboardInput.readLine()).charAt(0);
          if ((YesNo=='Y')||(YesNo=='y'))
            main(args);                        // Clumsy way of iterating,
                                               // but easiest solution.  
        }
      }
    

    Figure 7.7: Complete Implementation of Reverse Polish Evaluator using Stack Class.

Testing

The test conditions are summarised below:

Input Expected outcomeActual Outcome
@ Incorrect RPN expressionIncorrect RPN
+@ Incorrect RPN expressionIncorrect RPN
25@2525
'white space'@ Incorrect RPN expressionIncorrect RPN
25'white space'@2525
'white space'25'white space'@2525

Figure 7.8: Limit Test Results for RPN Application.

Input Expected outcomeActual Outcome
3 4 +@77
3 4 -@-1-1
3 4 *@1212
3 4 /@00
3 +@Incorrect RPNIncorrect RPN
3 4 + 5 6 *@Incorrect RPNIncorrect RPN
3 4 + 5 6 * +@3737
1 2 3 4 5 6 7 8 9 ++++++++@4545

Figure 7.9: Path Testing Results for RPN Application.


3. Summary

  1. Many Computer Science applications use models in which information can only be held and retrieved according to a precisely defined protocol. Among the most commonly used such regimes are the ADTs known as Stacks and Queues.
  2. Dynamic data structures offer a suitable implementation vehicle or realising both of these forms.
  3. The Stack ADT whose realisation was considered in this lecture, is widely used in a number of systems programming tools, such as high-level language compilers.
  4. The application presented in this lecture involving using a stack to evaluate an arithmetic expression in Reverse Polish Notation, is one such example. Although, in the compiler context, the algorithmic concern is to ensure that appropriate `low-level' code is prepared for evaluating an expression that contains references to variables, in practice it is a simple matter to develop the method above in order to cater for this.


(Notes prepared and maintained by Paul E. Dunne, November 1999)