【问题标题】:reversed polish giving wrong answer颠倒的波兰语给出错误的答案
【发布时间】:2017-03-20 13:08:12
【问题描述】:

我需要制作一个接受中缀表达式并使用 rpn 来计算它的计算器。

Java 代码:

public RpnCalculator() {

}


public float eval(float arg1, float arg2, String operator) {
    switch (operator) {
        case PLUS:
            return arg1 + arg2;
        case MINUS:
            return arg2 - arg1;
        case MULTIPLICATION:
            return arg1 * arg2;
        case DIVISION:
            return arg2 / arg1;
        default:
            return 0;
    }
}

public String evaluateInfixExpression(String expression) {
    Stack<String> operators = new Stack<>();
    String[] args = expression.split(SPACE);
    Stack<String> values = new Stack<>();

    for (String arg : args) {
        if (isANumber(arg)) {
            values.push(arg);
            continue;
        }
        if (operators.isEmpty()) {
            operators.push(arg);
        } else if (precedence(arg) <= precedence(operators.peek())) {
            float result = eval(Float.parseFloat(values.pop()), Float.parseFloat(values.pop()), operators.pop());
            values.push(String.valueOf(result));
            operators.push(arg);
        } else if (precedence(arg) > precedence(operators.peek())) {
            operators.push(arg);
        }
    }


    while (!operators.isEmpty()) {
        float result = eval(Float.parseFloat(values.pop()), Float.parseFloat(values.pop()), operators.pop());
        values.push(String.valueOf(result));
    }

    return expression;
}

public int precedence(String operator){
    if (operator.equals(PLUS) || operator.equals(MINUS)){
        return 1;
    }
    return 2;

}

public boolean isANumber(String number) {
    if (number.matches("-?\\d+")) {
        return true;
    }
    return false;
}

}

而且效果很好,只是有时会给出错误的答案... 在我看来,我正在遵循调车场算法原则,但正如你所见,我实际上并没有将中缀转换为后缀,但我尝试在旅途中评估参数,这可能是个问题。

例如表达式 -2 + 6 * 8 / 3 * 18 - 33 / 3 - 11 的计算结果为 286 而不是 264。应该有一些我无法注意到的错误,已经两天了,所以请帮我。此外,我在堆栈上阅读了很多关于 RPN 的线程,但似乎每个人都有不同的问题,所以我没有为我的案例找到答案。

谢谢。

【问题讨论】:

  • “使用 rpn 评估它”是什么意思。在您的程序中,您不使用 RPN。
  • 我的意思是我使用分流场原则将中缀转换为后缀,然后对其进行评估,因此:取arg1,取arg2并进行操作。

标签: java calculator rpn


【解决方案1】:

这是一个简单的即时计算解决方案:

public class RpnCalculator {
    public static Float evaluateInfixExpression(String inflixExpression) {
        Stack<Float> operands = new Stack<>();
        Stack<Operator> operators = new Stack<>();

        for (String token : inflixExpression.split("\\s")) {
            if (isOperator(token)) {
                while (!operators.isEmpty() && operators.peek().hasHigherPrecedenceThan(token))
                    operands.add(eval(operands.pop(), operands.pop(), operators.pop()));
                operators.push(fromString(token));
            } else {
                operands.add(new Float(token));
            }
        }

        while (!operators.isEmpty())
            operands.add(eval(operands.pop(), operands.pop(), operators.pop()));

        return operands.pop();
    }

    private static Float eval(float arg2, float arg1, Operator operator) {
        switch (operator) {
            case ADD:
                return arg1 + arg2;
            case SUBTRACT:
                return arg1 - arg2;
            case MULTIPLY:
                return arg1 * arg2;
            case DIVIDE:
                return arg1 / arg2;
            default:
                throw new IllegalArgumentException("Operator not supported: " + operator);
        }
    }
}

还有Operator 类:

public enum Operator {
    ADD(1), SUBTRACT(1), MULTIPLY(2), DIVIDE(2);
    final int precedence;
    Operator(int p) { precedence = p; }

    private static Map<String, Operator> ops = new HashMap<String, Operator>() {{
        put("+", Operator.ADD);
        put("-", Operator.SUBTRACT);
        put("*", Operator.MULTIPLY);
        put("/", Operator.DIVIDE);
    }};

    public static Operator fromString(String token){
        return ops.get(token);
    }

    public static boolean isOperator(String token) {
        return ops.containsKey(token);
    }

    public boolean hasHigherPrecedenceThan(String token) {
        return isOperator(token) && this.precedence >= fromString(token).precedence;
    }
}

【讨论】:

    【解决方案2】:

    我不是 RPN 专家,但是我注意到您正在按从右到左的顺序评估参数,因此在评估了乘法和除法之后,您最终会得到:

    operators = + - -
    values = -2 288 11 11
    

    然后你做(从右到左的顺序):

    11 - 11 = 0     // would expect -22 here
    288 - 0 = 288
    -2 + 288 = 286
    

    这没有给你正确的结果。

    如果你按从左到右的顺序计算,你会得到:

    -2 + 288 = 286
    286 - 11 = 275
    276 - 11 = 264
    

    所以我稍微修改了你的代码:

    public String evaluateInfixExpression(String expression) {
        Deque<String> operators = new LinkedList<>();
        String[] args = expression.split(SPACE);
        Deque<String> values = new LinkedList<>();
    
        for (String arg : args) {
            if (isANumber(arg)) {
                values.push(arg);
                continue;
            }
            if (operators.isEmpty()) {
                operators.push(arg);
            } else if (precedence(arg) <= precedence(operators.peek())) {
                float result = eval(Float.parseFloat(values.pop()), Float.parseFloat(values.pop()), operators.pop());
                values.push(String.valueOf(result));
                operators.push(arg);
            } else if (precedence(arg) > precedence(operators.peek())) {
                operators.push(arg);
            }
        }
    
        while (!operators.isEmpty()) {
            String v1 = values.removeLast();
            String v2 = values.removeLast();
            float result = eval(Float.parseFloat(v2), Float.parseFloat(v1), operators.removeLast());
            values.addLast(String.valueOf(result));
        }
        return expression;
    }
    

    【讨论】:

      【解决方案3】:

      对于 RPN,首先您应该将中缀形式转换为后缀形式。为此,您可以使用 Dijkstra 的 Shunting-yard algorithm

      此算法的示例实现:

      public class ShuntingYard {
          private static boolean isHigerPrec(String op, String sub) {
              return (ops.containsKey(sub) && ops.get(sub).precedence >= ops.get(op).precedence);
          }
      
          public static Stack<String> postfix(String infix) {
              Stack<String> output = new Stack<>();
              Deque<String> stack  = new LinkedList<>();
      
              for (String token : infix.split("\\s")) {
                  if (ops.containsKey(token)) {
                      while ( ! stack.isEmpty() && isHigerPrec(token, stack.peek()))
                          output.push(stack.pop());
                          stack.push(token);
                      }  else {
                          output.push(token);
                      }
              }
      
              while ( ! stack.isEmpty()) 
                  output.push(stack.pop());
              return reverse(output);
          }
      
          private static Stack<String> reverse(Stack<String> original) {
              Stack<String> reverse = new Stack<>();
              while(!original.isEmpty()) reverse.push(original.pop());
              return reverse;
         }
      }
      

      以及操作类:

      public enum Operator {
          ADD(1), SUBTRACT(1), MULTIPLY(2), DIVIDE(2);
          final int precedence;
          Operator(int p) { precedence = p; }
      
          public static Map<String, Operator> ops = new HashMap<String, Operator>() {{
              put("+", Operator.ADD);
              put("-", Operator.SUBTRACT);
              put("*", Operator.MULTIPLY);
              put("/", Operator.DIVIDE);
          }};
      
          public static Operator fromString(String str){
              return ops.get(str);
          }
      }
      

      你的班级终于修改了:

      public class RpnCalculator {
          private static Float eval(float arg1, float arg2, Operator operator) {
              switch (operator) {
                  case ADD:
                      return arg1 + arg2;
                  case SUBTRACT:
                      return arg2 - arg1;
                  case MULTIPLY:
                      return arg1 * arg2;
                  case DIVIDE:
                      return arg2 / arg1;
                  default:
                      throw new IllegalArgumentException("Operator not supported: " + operator);
              }
          }
      
          public static Float evaluateInfixExpression(String expression) {
              Stack<String> stack = ShuntingYard.postfix(expression);
              Stack<Float> result = new Stack<>();
              while(!stack.isEmpty()){
                  String nextElement = stack.pop();
                  if(isANumber(nextElement)){
                      result.push(new Float(nextElement));
                  } else {
                      result.push(eval(result.pop(), result.pop(), Operator.fromString(nextElement)));
                  }
              }
              return result.pop();
          }
      
          private static boolean isANumber(String number) {
              return number.matches("-?\\d+");
          }
      }
      

      资源:

      【讨论】:

      • 感谢您的全面回答。如您所见,我尝试在不翻译的情况下执行此操作,因此我希望即时执行所有评估。只是要明确一点-这是不可能的吗?
      • 我已经创建了another answer,它可以即时进行计算。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-11-19
      • 2020-02-16
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多