代码之家  ›  专栏  ›  技术社区  ›  sagi

Java计算器-调车场

  •  10
  • sagi  · 技术社区  · 7 年前

    我正在努力实现 Dijkstra's algorithm Shunting-yard 用简单的动作(+-/*)阅读数学方程式。它基本上得到一个“中缀”字符串并将其转换为“后缀”字符串。

    例如:输入-> "(3+5)*4-12" . Queue[3,5,+,4, *,12,-]

    从右到左阅读时,你会发现你需要从4的乘法中减去12,再加上3和5。

    我做得对。我认为将队列解释为计算的最简单方法是递归,因此我提出了以下代码:

    public static Expression newCalc(ArrayDeque<String> q)//q is the output of Shunting yard algo
    {
        String tmp =q.pollLast();
        if(tmp.equals("*") || tmp.equals("/") || tmp.equals("+") || tmp.equals("-")) {
            Expression rightOperation = newCalc(q);
            Expression leftOperation = newCalc(q);
            if(tmp.equals("+")) 
                return new Plus(leftOperation,rightOperation);
            else if(tmp.equals("-"))
                return new Minus(leftOperation,rightOperation);
            else if(tmp.equals("*"))
                return new Mul(leftOperation,rightOperation);
            else if(tmp.equals("/"))
                return new Div(leftOperation,rightOperation);
            else
                return new Number(0);
        }
        else 
            return new Number(Double.parseDouble(tmp));
    
    }
    

    它几乎适用于任何字符串,但以下字符串除外:

    "(3+5)*4-12+1"
    

    调车场后,队列输出为: [3,5,+,4, *,12,1,+,-]

    问题是,递归返回(3+5)*4-(12+1),这是错误的,我不知道如何解决这个问题(我知道我可以使用迭代解决方案,但我想了解如何使它工作)。

    谢谢

    编辑:

    我的调车场算法:

    public static double calc(String expression){
    
        Stack<String> s = new Stack<String>();  
        ArrayDeque<String> q = new ArrayDeque<String>();
        StringBuilder sb = new StringBuilder(expression);
        String token = new String();
    
        while((token = atoi(sb)) != null) {
        //atoi is a method that extract the correct next token ,cut it it from the string and return it.
            if(token.equals("/")|| token.equals("-")|| token.equals("+")|| token.equals("*")) {
                while ((token.equals("-")||token.equals("+"))&&
                        !s.isEmpty()&&
                        ((s.peek().equals("*")||s.peek().equals("/"))))
                    q.add(s.pop());
                s.push(token);
            }
            else if(token.equals("("))
                s.push(token);
            else if(token.equals(")"))
            {
                while(!s.peek().equals("("))
                    q.add(s.pop());
                s.pop();    
            }       
            else 
            {
                q.add(token);
            }
        }
        while(!s.isEmpty()&&(s.peek().equals("/")||s.peek().equals("*")||s.peek().equals("+")||s.peek().equals("-")))
            q.add(s.pop());
        return Math.floor(newCalc(q).calculate()*1000)/1000;
    
    }
    
    1 回复  |  直到 7 年前
        1
  •  2
  •   sagi    7 年前

    正如@BillTheLizard在对这个问题的评论中所建议的,递归很好,问题在于我的调车场算法。代码的UML表示,只有当一个运算符优先于另一个运算符时,才会替换两个运算符,但他们忘了提到,当两个运算符之间没有优先级时,我还需要保持运算符的原始顺序(特别是+和-在不同的执行顺序中有差异)。这解决了问题:

    while ((token.equals("-")||token.equals("+"))&& 
            !s.isEmpty()&&
            ((!s.peek().equals("(")&&!s.peek().equals(")")))) // I've changed this line
        q.add(s.pop());
    s.push(token);
    

    谢谢你的帮助。