Discussion Section 4
ECS 110 -- Spring 97
====================

This week:
----------

  o Using the string class to get tokens
  o Using a stack to traverse a tree


1. USING THE STRING CLASS TO GET TOKENS
---------------------------------------

In your current assignmnet, you are to evaluate formulas which look something
like

(Healthy(Ted) and (not Poor(Ted))) implies Happy(Ted).

Each formula is constructed of smaller distinct, meaningful elements called
tokens. The tokens in the above formula are:

'(' 'Healthy' '(' 'Ted' ')' 'and' '(' 'not' 'Poor' '(' 'Ted' ')' ')' ')'
'implies' 'Happy' '(' 'Ted' ')' '.'

Notice that the tokens are 1) Sequences of alphabetic characters, or 2) Single
non-alphabetic characters.

It would surely help you write your program if you had some function called
'get_next_token()' which would read from standard input the next meaningful
token. Hopefully you've already done so, but here is an alternative way using
some of the standard C++ libraries.

The idea is to return a token unless end-of-file has been reached, in which
case the empty string is returned. To do so, the function reads in an entire
line into a static string variable. [Remember that when a variable is declared
static within a function it means that at the beginning of the nth invocation
of the function, the static variable will have the same value as at the end of
the n-1'th invocation.] Then, whenever get_next_token is called, the token is
peeled off the front of the static string and returned. If ever the static
string is made empty, a new line is read into the static string.

#include <iostream.h>
#include <string>
#include <ctype.h>

const int max_line = 200;

string get_next_token(void)
{
  static string s("");
  string rs("");
  
  // Peel off white space and make sure s is non-empty
  do {
    if (s.length() == 0) {
      char buf[max_line];
      cin.getline(buf, max_line);
      s = buf;
    }
    int i = s.find_first_not_of(" \t\n");
    s.remove(0, i);
  } while ((s.length() == 0) && ( ! cin.eof()));
  
  if ( ! cin.eof()) {
    if (isalpha(s[0])) {
      // If the first character of the string is a letter
      // then get the word up to the next delimiter
      int n = s.find_first_of(".(), \t\n");
      rs.assign(s,0,n);
      s.remove(0,n);
    } else {
      // If the first character is not a letter, return it as a token
      rs = s[0];
      s.remove(0,1);
    }
  }
  return rs;
}

int main(void)
{
  while (get_next_token() != "") {
    
  }
  return (0);
}


2. USING A STACK TO TRAVERSE A TREE
-----------------------------------

Example from ECS 40 final exam.

(4) Recursion. [20] Assume we have the following structured type:

  struct node {
    int value;
    node *left;
    node *right;
  };
  
  typedef node* Nodeptr;

As you know, this defines the nodes for a binary tree. Write a recursive
function which adds all of the value members of all of the nodes in a binary
tree and returns the result. Additionally, fully document the function as
described in class. Here is the prototype you should follow:

  int total_value(Nodeptr np); 

/* ---------------------------------------------------------

  int total_value(Nodeptr np);

  total_value() sums all of the values of all of the 
  nodes in the tree pointed to by ÔnpÕ.

  np: (in) The root of the tree we wish to sum.
  return: the sum of all the nodes rooted at ÔnpÕ.
  PRE: ÔnpÕ is NULL or points to a legal binary tree.
  POST: The sum is returned, or 0 if ÔnpÕ is NULL.
  SIDE: None.
  NOTE: None.

--------------------------------------------------------- */

int total_value(Nodeptr np)
{
  if (np == NULL)
    return 0;
  else 
    return (np->value +
            total_value(np->left) + 
        total_value(np->right));
}

(5) Simulating Recursion Using Stack. [30] Each time a recursive function is
invoked, a new set of parameters and local variables are created on the runtime
stack. These parameters and local variables define a particular instance of the
problem. The problem is then divided into one or more smaller problems of
identical structure and the function is called recursively, placing yet more
(but smaller) problem instances onto the runtime stack. This is the principal
feature of recursion: problem instances are pushed onto the stack to be
completed later, after the smaller instances have completed.

You can take a similar approach writing an iterative solution and using a Stack
ADT. Just as a recursive solution pushes smaller problem instances onto the
runtime stack to be solved later, you can explicitly push smaller problems onto
the Stack ADT and solve them at your convenience.

Rewrite the function total_value(), but this time use no recursion and instead
use the Stack ADT from problem 2. You do not need to fully comment this
routine.

First rewrite the following typedef to hold the information you need.

   typedef int Stack_data_type;


  typedef Nodeptr Stack_data_type;


Now, rewrite total_value() non-recursively.

  int total_value(Nodeptr np); 

int total_value(Nodeptr np)
{
  int accum = 0;
  Nodeptr temp;
  Stack sp;

  sp.push(np);
  while ( ! sp.empty()) {
    temp = sp.top();
    sp.pop();
    if (temp != NULL) {
      accum += temp->value;
      sp.push(temp->left);
      sp.push(temp->right);
    }
  }
  return accum;
}
 

3. IF TIME REMAINS
------------------

If any time remains, then answer questions about hw 2.
