Java程序辅导

C C++ Java Python Processing编程在线培训 程序编写 软件开发 视频讲解

客服在线QQ:2653320439 微信:ittutor Email:itutor@qq.com
wx: cjtutor
QQ: 2653320439
Lab 4 
The Expression Trees 
Due Date 
Monday July 26h, 2010 by 11:59 PM 
 
GETTING STARTED 
Download the starter code file from /afs/andrew/course/15/111M08/downloads or course 
web 
  
THE BACKGROUND 
In this assignment you will write code for implementing an expression tree. Expression 
trees have many applications in areas such as symbolic manipulators (eg: Mathematica) 
where a symbolic expression can be represented as a binary tree.  
An expression tree is a binary tree that models an expression. For example, the 
expression ((1+2)*(3-(4/5))) is modeled by a tree that looks like this: 
 
 
 
We can use expression trees to manipulate expressions. First we will understand some 
basic operations that we can perform on an expression tree. 
Commute Operation 
Consider commute operation for an operator. For example we know that a*b = b*a, 
where a and b are expressions. This can be shown by a tree as given below. If both trees 
evaluates to the same value, then the operator commutes (at least for that example)  
  
The commute operation swaps the left and right sub trees of an expression: (a*b)  
(b*a). For the addition and multiplication operators, the value of the expression remains 
the same after the commute. For the subtraction and division operators, the value of the 
expression may change.  
Mutating and Non-Mutating Transformations 
A non-mutating transformation is one that does not change the data structure. Instead, it 
creates new nodes to return (and leaves the old nodes as they are). For example, a non-
mutating commute operation looks like this:  
 
 
The old node (shown in gray) still exists, and anyone who had a pointer to it can still use 
it. The commute operation added a new node which represents the tree after the 
commute.  
This sort of operation is useful if you're dealing with "somebody else's data"---if 
somebody else created this tree, and might still be planning to use it after you're done 
with it. This is also useful for keeping track of the history of your data structure: you can 
save a pointer to your tree after each operation, and if later someone says, "Hey, what did 
that tree look like after you inserted ten keys?", you'll be able to tell them.  
Unless the compiler is really clever (wait until 15-212 for more about this), a strict 
regime of non-mutation can result in a lot of space being consumed, resulting in more 
frequent garbage collections and possibly in filling up the heap unnecessarily. But 
mutation can be risky if there is a possibility that other parts of your program also 
reference the mutated structures -- if they don't expect changes to be made, you can have 
some hard-to-debug errors! Every time you do a commute, you've created another 
treenode. Java's automatic garbage-collection will take care of the treenodes you didn't 
need, but there is a caveat. Garbage-collection affects performance, because it involves 
checking all allocated objects to see if they are still referenced and accessible. When the 
programmer is confident that it is safe to mutate objects, fewer new objects are made, 
which can reduce the amount of storage allocation and so reduce the frequency of 
garbage collection.  
For some applications you need mutating transformations. A mutating transform reaches 
into the tree and swaps around pointers until the tree looks like it should. For example, 
here's a mutating commute transform:  
 
 
Mutating transforms are nice because they don't waste space on unnecessary treenodes. In 
this assignment you'll implement both mutating and nonmutating commute methods. 
 
 The Assignment 
 
We strongly encourage you to open the starter code files and get yourself familiar with 
the assignment requirements. In the starter code you will find a bunch of java files, 
consisting of classes, abstract classes (will be discussed in class) and interfaces. An 
interface is a collection of standard methods that an implementing class will “implement” 
their own way. An abstract class is a collection of generic methods that have been 
implemented that another class can extend. Abstract classes cannot be instantiated to 
create objects. For example, we can have a “vehicle” class, but a specific vehicle such as 
a Toyota can be extended from a generic vehicle definition to add methods and states that 
are specific to “Toyotas”. Here are the given files. 
• Expression.java is an interface which our expression treenodes will implement. It 
supports three operations: toString(), height(), and compute(). Read the method 
descriptions, but do not modify this file. 
• FloatNode.java contains code for a node that just holds a float. 
• OperatorNode.java is an abstract class which the AddNode, SubNode, 
MultNode, and DivNode classes will inherit from. There are a number of methods 
which are not marked as abstract, and so are to be filled in here. For now, fill in 
the method body for toString() and height(). We'll come back to the rest later.  
• AddNode.java and SubNode.java contain code for the addition and subtraction 
nodes in the evaluation tree. We've filled in the constructor and createNew() 
methods for you; look at them to see how they work, but you only need to fill in 
the compute() method.  
Pay particular attention to the createNew() method, because it's kind of tricky. 
Calling createNew() on an OperatorNode returns a new OperatorNode with the 
same operator. For example, calling createNew() on an AddNode returns another 
AddNode. You can use this on an OperatorNode even if you don't know what 
type it is. This method will be useful for writing non-mutating transformations.  
• MultNode.java and DivNode.java should contain code for the multiplication and 
division nodes in the evaluation tree. Fill in the constructor, createNew(), and 
compute() methods. You can look at AddNode and SubNode for examples - the 
code will be quite similar. 
• You've now completed the basic structure of the expression tree. Use the file 
Driver.java to test your code. Feel free to add your own tests. This file will not be 
graded. Don't be alarmed when your commute method return null - you haven't 
implemented them yet. 
 
 
Implementing the Commute Method 
Now it's time to add commute method to the structure. We'll add mutating and 
nonmutating versions of each one, and track the space usage of the structure as a whole.  
• To begin, we need a way to track space usage. For this we'll use a method in 
OperatorNode called getNumCreated(). This method will track the total number 
of OperatorNodes created since the program began. Fill in the method body. To 
make this work, you'll need to add a static variable to the OperatorNode class, and 
increment the static variable every time the OperatorNode constructor is called. 
Making the variable static ensures that all OperatorNode objects share the same 
copy of the variable. You can initialize the variable to zero when you declare it. 
• Next, fill in the commute() and commuteMutating() methods. The commute() 
method should create one new node; the commuteMutating() method should not 
create any new nodes. The createNew() method, from before, will be useful here.  
You may find the keyword "this" useful. When you're inside an object, "this" is a 
pointer to the object you're inside. So, for example, you can go return this; 
to return a pointer to the current object.  
• Test your code using the file Driver.java. Add your own tests where you feel it's 
appropriate. Expressions are added manually in the driver program. Your program 
must pass all those tests to get the credit. Once you're sure everything works, 
create a zip file with at least the files you are to change:  
o SubNode.java 
o AddNode.java 
o MultNode.java 
o DivNode.java 
o OperatorNode.java 
Grading: 
100 points total, distributed as follows:  
o SubNode.java : 10 points 
o AddNode.java :  10 points 
o MultNode.java : 10 points 
o DivNode.java : 10 points 
o OperatorNode.java : 30 points 
o Passing our test cases : 20 points  
o Style: Commenting and indenting and others: 10  
Make sure that your program compiles and runs properly. As usual, take the 10 style 
points seriously; poorly commented spaghetti code is not acceptable.   
 
Where to Submit: 
Go to afs/andrew.cmu.edu/course/15/111M08/handin and submit zip file under Lab4