Creating a "calculator" to evaluate arithmetic expressions in Java - code troubles
我试图通过创建一个简单的计算器来处理涉及括号的算术表达式来巩固我对堆栈和运算符的理解。我觉得我的代码应该可以工作,但它肯定不会给我正确的输出。
尽管我有一个方法来评估每个表达式,但当我尝试返回数字堆栈时,它不会打印出任何评估的方法,而只会打印出用户输入的所有数字。我也想处理输入中的问题,例如不匹配的运算符或缺少括号。
我尝试使用 9 * 5 或 (7 * 6) (9 - 4) 之类的简单表达式运行代码,但无论如何它都会返回最后一个双精度数。
到目前为止,这是我的代码:
主要方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 | import java.util.Stack; import javax.swing.JOptionPane; public class Calculator { // instance variables private Stack < Double > nums; private Stack < String > ops; String list; // constructor public Calculator() { nums = new Stack < Double > (); ops = new Stack < String > (); } // methods public static boolean isDouble(String str) { try { Double.parseDouble(str); } catch (NumberFormatException e) { return false; } catch (NullPointerException e) { return false; } return true; } public static boolean isValidOp(String str) { return (str =="(" || str ==")" || str =="^" || str =="*" || str =="/" || str =="+" || str =="-"); } public int prec(String str) { if (str =="(" || str ==")") return 4; if (str =="^") return 3; if (str =="*" || str =="/") return 2; if (str =="+" || str =="-") return 1; else return -1; } public double applyOperator(double left, String op, double right) { if (op =="+") { return (left + right); } if (op =="-") { return (left - right); } if (op =="*") { return (left * right); } if (op =="/") { return (left / right); } if (op =="^") { return Math.pow(left, right); } else { throw new IllegalArgumentException("Not a valid operator"); } } public String evaluate(String str) { String [] tokens = str.split(""); for (int i = 0; i < tokens.length; i++) { if (isDouble(tokens [i]) == true) { nums.push(Double.parseDouble(tokens [i])); } if (tokens [i] =="(") { ops.push(tokens [i]); } if (tokens [i] ==")") { String op1 = ops.pop(); double num1 = nums.pop(); double num2 = nums.pop(); double result = applyOperator(num1,op1,num2); nums.add(result); } if (tokens [i] =="+" || tokens [i] =="-" || tokens [i] =="*" || tokens [i] =="/" || tokens [i] =="^") { if(ops.isEmpty()) { ops.push(tokens [i]); } else if (prec(tokens [i]) > prec(ops.peek())) { ops.push(tokens [i]); } else if (prec(tokens [i]) < prec(ops.peek()) && !ops.isEmpty() && ops.peek() !="(") { String ac1 = ops.pop(); double res1 = nums.pop(); double res2 = nums.pop(); double outcome = applyOperator(res1,ac1,res2); nums.add(outcome); } } } while(!ops.isEmpty() && nums.size() > 1) { String ab = ops.pop(); double bb = nums.pop(); double cb = nums.pop(); double clac = applyOperator(bb,ab,cb); nums.add(clac); } String fix = nums.pop().toString(); return fix; } } |
测试者:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | import javax.swing.JOptionPane; public class AppforCalc { public static void main(String [] args) { Calculator calc = new Calculator(); String reply ="yes"; String instructions ="Enter a mathematical expression. Separate everything with spaces"; while(reply.equalsIgnoreCase("yes")) { String expression = JOptionPane.showInputDialog(instructions); String ans = calc.evaluate(expression); reply = JOptionPane.showInputDialog("The solution is" + ans +"Try again?"); } } } |
算法失败的主要原因是在尝试检查
在Java 中,
计算器的行为存在更多问题(算法问题),但在处理字符串相等检查后,这些问题将更容易识别和修复。必须解决的问题的一个示例是:
1 2 3 4 5 6 7 8 | while(!ops.isEmpty() && nums.size() > 1) { String ab = ops.pop(); double bb = nums.pop(); double cb = nums.pop(); double clac = applyOperator(bb,ab,cb); nums.add(clac); } |
操作数(
另一个问题如下:
1 2 3 4 5 6 7 8 | else if (prec(tokens [i]) < prec(ops.peek()) && !ops.isEmpty() && ops.peek() !="(") { String ac1 = ops.pop(); double res1 = nums.pop(); double res2 = nums.pop(); double outcome = applyOperator(res1,ac1,res2); nums.add(outcome); } |
进行了内部评估,但评估的触发是发现具有较低存在的操作数。运算后应将操作数推入操作堆栈:
1 2 3 4 5 6 7 | else if (prec(tokens [i]) < prec(ops.peek()) && !ops.isEmpty() && ops.peek() !="(") { ... ... nums.add(outcome); // I highly suggest refactoring this to nums.push due to readability considerations ops.push(tokens[i]); } |
参考文献:
- Java中==和equals的区别
- 实现科学计算器的指南(在 c 中,用作算法参考)
- 调车场算法 - 正如 user207421 所建议的那样