【发布时间】:2014-12-04 19:23:39
【问题描述】:
我是 Java 新手,正在尝试将评估方法添加到我的课程中。 ExpTree 类和它的测试程序给了我。我按照我在课堂上学到的代码编写了代码,但不知道为什么它不起作用。
evaluate() 方法,它返回 ExpTree 的算术评估。这应该以递归方式完成,因此您将需要 2 种方法来完成它。在导致除以 0 或取模的情况下,它应该抛出一个带有描述性字符串的新 ArithmeticException。如果树为空,evaluate() 还应该抛出一个带有描述性字符串的新 ArithmeticException。
这是我的代码:
// This will implement an "Expression Tree" which stores an arithmetic expression
import java.util.*;
public class ExpTree
{
//-------data
private ExpNode root;
//-------constructor
public ExpTree()
{
root = null;
}
//constructor where a string is passed in. It is parsed and stored
public ExpTree(String expString)
{
//declare StringTokenizer, Stacks, and other variables used in parsing
StringTokenizer tokenizer = new StringTokenizer (expString, "()+-*/%", true);
String token;
ExpNode operator, leftOperand, rightOperand;
Stack<ExpNode> operators = new Stack<ExpNode>();
Stack<ExpNode> operands = new Stack<ExpNode>();
//break up expString into tokens
while (tokenizer.hasMoreTokens())
{
token = tokenizer.nextToken();
// if the current token is a left paren, ignore it
if (token.equals ("("))
;
// if the current token is an operator, put it on the
// operator stack
else if ((token.equals ("+")) || (token.equals ("-")) ||
(token.equals ("*")) || (token.equals ("/")) || (token.equals ("%")))
operators.push (new ExpNode(token));
//if the current token is a right paren, pop the operators stack
//to get the operator, pop the operands stack twice to get the two
//operands (stored as expression trees). Then make the two operands
//children of the operator and push back on the operands tree.
else if (token.equals (")"))
{
operator = operators.pop();
rightOperand = operands.pop();
leftOperand = operands.pop();
operator.setLeft(leftOperand);
operator.setRight(rightOperand);
operands.push(operator);
}
//otherwise, the token should be a number - put it in the operands stack
else
operands.push (new ExpNode(token));
} // while (tokenizer.hasMoreTokens())
//when finished parsing, the operands stack should contain the fully-built
//expression tree.
if (!operands.isEmpty())
root = operands.pop();
}
//-------methods
//isEmpty()
public boolean isEmpty()
{
return (root == null);
}
//printTree methods - prints the tree in RNL order, with indents. Called from "outside"
public void printTree()
{
if (root == null)
System.out.println("The tree is empty");
else
printTree(root, 0); //start with the root with 0 indentations
}
//recursive, private version of printTree
private void printTree(ExpNode subTree, int indents)
{
//if there is a right side, handle it first (with 1 more indent)
if (subTree.getRight() != null)
printTree(subTree.getRight(), indents+1);
//then print the node itself (first move over the right amount of indents)
System.out.println("\n\n\n");
for (int i=0; i<indents; i++)
System.out.print("\t");
System.out.println(subTree);
//if there is a left side, handle it first (with 1 more indent)
if (subTree.getLeft() != null)
printTree(subTree.getLeft(), indents+1);
}
//inorder traversal - starts the recursive calls to print inorder
public String inOrder()
{
return inOrder(root);
}
//inorder traversal - recursive left side of tree, print node, right side of tree
private String inOrder(ExpNode theTreeToTraverse)
{
if (theTreeToTraverse == null)
return ""; //don't try to do anything if tree is null
//else build up a String to return. It will involve recursive calls
String returnString = "";
if (theTreeToTraverse.getLeft() != null)
{
returnString += "(" + inOrder(theTreeToTraverse.getLeft());
}
returnString += theTreeToTraverse;
if (theTreeToTraverse.getRight() != null)
{
returnString += inOrder(theTreeToTraverse.getRight()) + ")";
}
return returnString;
}
//public version of evaluate
public double evaluate(){
if (root == null) //Am I null?
throw new ArithmeticException("The tree is empty, nothing to be evaluated!");
else //You handle it!
return recursiveEvaluate(root);
}
//Recursive version of evaluate
private double recursiveEvaluate(ExpNode subTree){
//If subTree is empty
if (subTree == null)
return 0;
//What are you subTree? A number? An operator?
else if(subTree.getData().equals("+"))
return recursiveEvaluate(subTree.getLeft()) +
recursiveEvaluate(subTree.getRight()) ;
else if(subTree.getData().equals("-"))
return recursiveEvaluate(subTree.getLeft()) -
recursiveEvaluate(subTree.getRight()) ;
else if(subTree.getData().equals("*"))
return recursiveEvaluate(subTree.getLeft()) *
recursiveEvaluate(subTree.getRight()) ;
else if(subTree.getData().equals("/")){
double right = recursiveEvaluate(subTree.getRight());
if(right == 0.0)
throw new ArithmeticException("Divide by zero is undefined!");
return recursiveEvaluate(subTree.getLeft()) / right;
}
else if(subTree.getData().equals("%")){
double right = recursiveEvaluate(subTree.getRight());
if(right == 0.0)
throw new ArithmeticException("Mod by zero exception");
return recursiveEvaluate(subTree.getLeft()) % right;
}
//Converting String type to double
else
return Double.parseDouble(subTree.getData());
}
//Public version of numPlus
public int numPlus(){
return recursiveNumPlus(root);
}
//Recursive version of numPlus
private int recursiveNumPlus(ExpNode subTree){
if (subTree == null)
return 0;
//If you are a '+' sign
if(subTree.getData().equals("+"))
return recursiveNumPlus(subTree.getLeft()) +
recursiveNumPlus(subTree.getRight()) + 1;
else
return recursiveNumPlus(subTree.getLeft()) +
recursiveNumPlus(subTree.getRight());
}
}
//***************************************************************************
// ExpNode holds a "node" for an ExpTree.
class ExpNode
{
//data
private String data;
private ExpNode left;
private ExpNode right;
//constructor
public ExpNode(String el)
{
data = el;
left = right = null;
}
//methods
//toString() - this is how an ExpNode represents itself as a String
public String toString()
{
return data;
}
//getLeft - returns the reference to the left subTree
public ExpNode getLeft()
{
return left;
}
//getRight - returns the reference to the right subTree
public ExpNode getRight()
{
return right;
}
//getData - returns the data (could be an operator or a number, so returns as a String)
public String getData()
{
return data;
}
//setLeft - sets the left subTree to whatever is passed in
public void setLeft(ExpNode newNode)
{
left = newNode;
}
//setRight - sets the right subTree to whatever is passed in
public void setRight(ExpNode newNode)
{
right = newNode;
}
}
【问题讨论】:
-
树实际存储了什么样的东西,评估它意味着什么?
-
只是数字、int 和 double。这意味着如果树中有任何数学运算,此方法必须对其进行评估!例如,如果我们通过 3 + 5,我们应该得到 8 作为输出!
-
如果你能展示一个完整的课程会更容易提供帮助。
recursiveEvaluate是ExpNode的成员吗?getLeft和getRight是否返回另一个ExpNode?如果是这样,您的代码应该看起来像return this.getLeft().evaluate() + this.getRight().evaluete()。在这种情况下,您不需要两个功能。或者你可能应该实现 Visitor Pattern? -
所以是数字和运算符?数字有不同的数据类型?看起来您已经编写了一些很好的代码来计算树中的节点数,但您也需要以某种方式查看数字和运算符。
-
@5gon12eder 实际上,Ava 的结构方式与您的建议相同。问题是缺少很多东西——不是
recursiveEvaluate是否应该有ExpNode作为参数。
标签: java recursion methods expression-trees evaluate