Java - Stack.pop不返回添加的最后一项

时间:2016-10-07 15:29:43

标签: java android

在自学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

2 个答案:

答案 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的值,以便更好地了解它,为什么它的行为就像它一样。