在自学Android编程(使用Android Studio)时,我正在开发一个基本的计算器应用程序。我的eval方法使用Dijkstra的shunting-yard算法来解析字符串表达式并计算结果。我从this SO question得到了这个想法。
我的Evaluator类的代码如下:
class Evaluator {
private static Evaluator instance = new Evaluator();
private Stack< String > mOperators;
private Stack< Double > mOperands;
public static Evaluator getInstance() {
return instance;
}
private Evaluator() {
mOperands = new Stack< Double >();
mOperators = new Stack< String >();
}
public Double eval( String expression ) {
Stack stack = convertExpressionToStack( expression );
buildOperationStacks( stack );
return doEval();
}
private Double doEval() {
while ( !mOperators.isEmpty() ) {
String op = mOperators.pop();
Double v = mOperands.pop();
switch ( op ) {
case "+":
v = mOperands.pop() + v;
break;
case "-":
v = mOperands.pop() - v;
break;
case "*":
v = mOperands.pop() * v;
break;
case "/":
v = mOperands.pop() / v;
break;
}
mOperands.push( v );
}
return mOperands.pop();
}
private void buildOperationStacks( Stack stack ) {
while ( !stack.isEmpty() ) {
String s = ( String ) stack.pop();
switch ( s ) {
case "+":
case "-":
case "*":
case "x":
case "X":
case "/":
case "÷":
if ( s.equals( "x" ) || s.equals( "X" ) ) {
s = "*";
} else if ( s.equals( "÷" ) ) {
s = "/";
}
mOperators.push( s );
break;
default:
try {
if ( !stack.isEmpty() && stack.peek().equals ( "." ) ) {
s += stack.pop();
s += stack.pop();
}
mOperands.push( Double.parseDouble( s ) );
} catch ( Exception e ) {
Log.e( "Error", e.getMessage() );
}
}
}
}
private Stack convertExpressionToStack( String expression ) {
Stack< String > s = new Stack< String >();
for ( char c : expression.toCharArray() ) {
s.push( String.valueOf( c ) );
}
return s;
}
}
所以我的问题在于doEval方法。当我从每个堆栈中弹出元素时,我将第一个元素添加到每个堆栈中。我的印象是堆栈是First In Last Out结构。
那么我可能做错了什么?我是否需要以某种方式反转每个堆栈?
谢谢。
修改
例如,我输入5 + 3 * 2。我希望执行是
pass 1: value1 = 2, Operator1 = *, value2 = 3 result = 6
pass 2: Value1 = 6 (result of pass 1) Operator1 = +, value2 = 5 result = 11
然而,当我调试这个时,我看到了:
pass 1: value1 = 5, Operator1 = +, value2 = 3, result = 8
pass 2: value1 = 8 (result of pass 1), operator1 = *, value2 = 2, result = 16
答案 0 :(得分:3)
您的convertExpressionToStack()
方法正在以正确的顺序构建操作数堆栈,然后您的buildOperstionStack()
方法将其反转,方法是弹出一个并推送另一个。
您还不需要第二种方法:只需更改评估方法,将x
理解为乘法等。
答案 1 :(得分:0)
您对Stack的理解是正确的。它是第一个,最后一个或最后一个,先出。
关于您的代码:
while ( !mOperators.isEmpty() ) {
String op = mOperators.pop();
Double v = mOperands.pop();
switch ( op ) {
case "+":
v = mOperands.pop() + v;
break;
case "-":
v = mOperands.pop() - v;
break;
case "*":
v = mOperands.pop() * v;
break;
case "/":
v = mOperands.pop() / v;
break;
}
mOperands.push( v );
}
因为,你没有提到,它究竟是如何表现的,所以,让我解释一下。假设,mOperators有+, - 其中+首先添加+, - 在+
之上mOperands has 3,6,2,1
这就是您的代码将如何表现的行为。
对于while循环的第一次迭代:
op = -
v = 1
v = 2-1 = 1 // since it's a -
mOperands is now: 3,6
并且在通话结束后,mOperands.push(v),因为v现在是1,你的mOperands将是:
3,6,1
while循环的第二次迭代:
op = +
v = 1
v = 6+1 = 7 // since op is +
您的mOperands现在看起来像:3
一旦它从交换机断开,它将使mOperands成为:
3,7
P.S:你应该调试你的应用程序,以便在每一步看到mOperands的值,以便更好地了解它,为什么它的行为就像它一样。