如何在Java中正确实现含关系、逻辑运算符的后缀表达式求值?
现有代码核心问题
isOperator判断逻辑不合理:仅通过首个字符是否为字母/数字判定是否为运算符,易误判特殊输入,建议改用运算符白名单校验- 逻辑运算符实现错误:
&&、||目前使用按位与&、按位或|实现,和实际逻辑运算规则不符。逻辑运算仅需判断操作数是否非零,无需按位计算 ^运算符歧义:当前代码实现为按位异或,若业务中^表示幂运算,需改用Math.pow实现- 栈和队列未指定泛型:操作时需要反复强转类型,容易出现类型转换异常
修复后代码
import java.util.*; public class PostEvaluator { // 运算符白名单,避免误判 private static final Set<String> OPERATORS = new HashSet<>(Arrays.asList( "*", "/", "+", "-", "%", "^", ">", "<", ">=", "<=", "!=", "==", "&&", "||", "!" )); private Stack<String> stack; private Queue<String> queue; public PostEvaluator() { stack = new Stack<>(); queue = new LinkedList<>(); } private static boolean isOperator(String c) { return OPERATORS.contains(c); } private int operate(int x, int y, String operator) { switch (operator) { case "*": return x * y; case "/": if (y == 0) { System.out.println("Division by zero error!"); System.exit(0); } return x / y; case "+": return x + y; case "-": return x - y; case "%": return x % y; case "^": // 若为幂运算请替换为下面的代码 // return (int) Math.pow(x, y); // 当前保留按位异或逻辑 return x ^ y; case ">": return x > y ? 1 : 0; case "<": return x < y ? 1 : 0; case ">=": return x >= y ? 1 : 0; case "<=": return x <= y ? 1 : 0; case "!=": return x != y ? 1 : 0; case "==": return x == y ? 1 : 0; case "&&": // 逻辑与:两个操作数都非零返回1,否则0 return (x != 0 && y != 0) ? 1 : 0; case "||": // 逻辑或:任意一个操作数非零返回1,否则0 return (x != 0 || y != 0) ? 1 : 0; default: System.out.println("Unknown operator: " + operator); System.exit(0); return 0; } } private int notOperate(int x) { return x == 0 ? 1 : 0; } public String evaluatePostFix(String input) { String val1, val2, result = "", temp; int intVal1, intVal2; Scanner kb = new Scanner(input); kb.useDelimiter(" "); while (kb.hasNext()) { // 若使用自定义Queue,请替换为你自己的enqueue方法 queue.offer(kb.next()); } while (!queue.isEmpty()) { // 若使用自定义Queue,请替换为你自己的dequeue方法 temp = queue.poll(); if (temp.isBlank()) continue; if (!isOperator(temp)) { stack.push(temp); if (result.equals("")) { result = temp; } } else { if (stack.isEmpty()) { System.out.println("Missing Operand/s Error"); System.exit(0); } if (!temp.equals("!")) { val1 = stack.pop(); if (stack.isEmpty()) { System.out.println("Missing Operand/s Error"); System.exit(0); } val2 = stack.pop(); intVal1 = Integer.parseInt(val1); intVal2 = Integer.parseInt(val2); result = Integer.toString(operate(intVal2, intVal1, temp)); stack.push(result); } else { val1 = stack.pop(); intVal1 = Integer.parseInt(val1); result = Integer.toString(notOperate(intVal1)); stack.push(result); } } } // 最后校验栈中是否只剩一个结果,否则说明表达式不合法 if (stack.size() != 1) { System.out.println("Invalid expression error"); System.exit(0); } return stack.pop(); } }
补充说明
后缀表达式求值的逻辑本身和运算符类型无关,只要保证运算符的运算逻辑正确、中缀转后缀时的运算符优先级和结合性处理正确即可,关系/逻辑运算符的求值规则和算术运算符一致,都是遇到运算符就弹出对应数量的操作数计算后将结果压回栈。如果你使用的是自定义的Stack和Queue实现,把代码中对应栈队列的操作换回你自己的方法即可。
内容的提问来源于stack exchange,提问作者Wreckzonee
相关产品推荐
相关产品推荐

