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 #include #include 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.