Colorado State University Computer Science Department

CS-200, Spring 1999
Assignment #8


Description with Sample Output

For this assignment, you will convert an arithmetic expression, like ( 3 + 4.5 ) * 2 given as a String, into a binary tree representation. You will use the binary tree to print the expression as a prefix, infix, and postfix expression by traversing the tree in pre-order, in-order, and post-order, respectively. You will also use the tree to evaluate the expression.

Expressions will only contain the binary operators +, -, *, and /. No unary operators, like - 2, are allowed. Numbers can be any valid double. If an expression includes parentheses, the parentheses must be separated by a space from other tokens. This will allow you to use StringTokenizer to extract each item from the String expression. Also, assume that the expression does not include any redundant parentheses. In other words, expressions like 3.2 + ( ( 2 * 4 ) ) and 64 - ( 2 / 3 ( ) ) are not legal. Your program does not have to handle these illegal expressions.

Write your program so that the expression is given as a command line argument. Given this String, your program must do the following steps:

  1. Print the argument as a String.
  2. Convert the String expression into a binary tree.
  3. Print a diagram of the binary tree as shown below.
  4. Print the pre-order, post-order, and in-order traversals of the binary tree representation of the expression.
  5. Evaluate the expression and print the resulting value.
Your output should look like this example:
-> java main "3 + 5.5"

--------New Expression---------
3 + 5.5

Preorder:  + 3.0 5.5 
Postorder: 3.0 5.5 + 
Inorder:   3.0 + 5.5 

Evaluation: 8.5
-> 

You can write a simple shell script to test a number of expressions. For example, if I create a file named testexp with the following lines:

java main "4.1 + 3"
java main "4.1 - 3"
java main "4.1 * 3"
java main "4.1 / 3"
java main "3 + 4 * 2"
java main "3 + ( 4 * 2 )"
java main "3 + ( ( 12.5 / 6.7 ) + ( 4 * 2 ) )"
java main "3 + ( 5 - 6 ) * ( 50 - 2 / 2 )"
and then make it executable by doing
chmod a+x testexp
and then running it by typing
testexp
I get the following output.
--------New Expression---------
4.1 + 3

Preorder:  + 4.1 3.0 
Postorder: 4.1 3.0 + 
Inorder:   4.1 + 3.0 

Evaluation: 7.1

--------New Expression---------
4.1 - 3

Preorder:  - 4.1 3.0 
Postorder: 4.1 3.0 - 
Inorder:   4.1 - 3.0 

Evaluation: 1.0999999999999996

--------New Expression---------
4.1 * 3

Preorder:  * 4.1 3.0 
Postorder: 4.1 3.0 * 
Inorder:   4.1 * 3.0 

Evaluation: 12.299999999999999

--------New Expression---------
4.1 / 3

Preorder:  / 4.1 3.0 
Postorder: 4.1 3.0 / 
Inorder:   4.1 / 3.0 

Evaluation: 1.3666666666666665

--------New Expression---------
3 + 4 * 2

Preorder:  * + 3.0 4.0 2.0 
Postorder: 3.0 4.0 + 2.0 * 
Inorder:   3.0 + 4.0 * 2.0 

Evaluation: 14.0

--------New Expression---------
3 + ( 4 * 2 )

Preorder:  + 3.0 * 4.0 2.0 
Postorder: 3.0 4.0 2.0 * + 
Inorder:   3.0 + 4.0 * 2.0 

Evaluation: 11.0

--------New Expression---------
3 + ( ( 12.5 / 6.7 ) + ( 4 * 2 ) )

Preorder:  + 3.0 + / 12.5 6.7 * 4.0 2.0 
Postorder: 3.0 12.5 6.7 / 4.0 2.0 * + + 
Inorder:   3.0 + 12.5 / 6.7 + 4.0 * 2.0 

Evaluation: 12.865671641791044

--------New Expression---------
3 + ( 5 - 6 ) * ( 50 - 2 / 2 )

Expression tree:
      2.0
   /
         2.0
      -
         50.0
*
         6.0
      -
         5.0
   +
      3.0


Preorder:  * + 3.0 - 5.0 6.0 / - 50.0 2.0 2.0 
Postorder: 3.0 5.0 6.0 - + 50.0 2.0 - 2.0 / * 
Inorder:   3.0 + 5.0 - 6.0 * 50.0 - 2.0 / 2.0 

Evaluation: 48.0

Converting the String Expression into a Binary Tree

This part of the problem is usually referred to as parsing the expression. We will make heavy use of recursion to build the tree. The first thing to realize is that any expression consists of term-operator-term sequences, where each term might be another expression.

First, let's define a method that is called to start converting the string into a binary tree. It will also be used to build a subtree for any expression that is surrounded by parentheses. Use a StringTokenizer object to keep track of the remaining unconverted expression. So, this method must receive as arguments the StringTokenizer object and a String that tells the method when to stop converting. If it is being used to convert just an expression between ( and ), then the second argument should be ")". The first time it is called, the second argument should be null, indicating that the method should continue to convert the expression until no more tokens are available. Let's call this method buildExpTree. It calls another method, buildTerm, defined below. Here are the steps that buildExpTree should follow:

This method calls buildTerm to create either a leaf node containing a number or a subtree representing a parenthesized expression. buildTerm just needs the StringTokenizer as an argument, and it follows these steps:

Traversals

You already know how to traverse a binary tree. As discussed in class, the body for each traversal method will only require about four lines. Do not write general traversal methods---just write specific ones that simply print the value of node passed in as an argument and, of course, recurse on the left and right children.

To print the side-ways diagram of the tree, traverse the tree in-order, but swap the order of visiting the right and left children. Pass a second argument to this method that is an int whose value is the depth of the node passed in as the first argument. Use the depth to decide how many spaces to print before printing the value of the node. The result will be a tree that looks correct when you turn your paper 1/4 turn clockwise. For example, the diagram below on the left is what you will print. It represents the tree on the right:

      3	       	       	         +        
   *			        / \       
      6.4   		    3.4    *      
+			          / \     
   3.4			        6.4  3    
 

You will end up with a total of four traversal methods, three to simply print the pre, in, and post-order expression, and one to print the diagram.

Evaluating the Expression

Now that the expression is represented as a binary tree, it is extremely easy to evaluate using a recursive method. Simply evaluate the left child and the right child of the root node, then combine the results using the operator stored in the root node.

This recursive method must first check to see if the left child of the node passed in as an argument is not null. If the left child is null, then it simply returns the double value of the argument.

Structure of Code

In addition to the main class, you will need a class to define a binary tree node. Do not define a complete BinaryTree class like the one in the text book, just define the class for a binary tree node. Include this as an inner class in your main.java file. All other methods you are writing will be methods in the main class. This way you will end up with a single java file.

Suggestions

Since you are developing a single Java file, you will have to be creative in dividing this problem among your team members and testing each part. Converting the String expression into a binary tree will be the hardest part. While one or two work on that part, the others could write some temporary code to build a simple binary tree that can be passed to the traversal methods to test them. A hand-coded valid expression tree can be be passed to the evaluation method to test it.

Make heavy use of the traversal method that prints the tree diagram. This can be used to print a diagram of the whole tree or any subtree. You can observe the construction of your expression tree by sprinkling calls to your diagram method within the construction code.

What to Check In

Electronically check in one file, Main.java, using a file appendage of .p

See the Checkin documentation to check in your files if you need to.


Return to CS-200 Home Page

Copyright © 1997, 1998, 1999: Colorado State University for CS200. All rights reserved.