如何在Java中实现支持运算优先级与括号的计算器?
实现支持括号与运算优先级的计算器
你现在要做的是表达式求值器,和基础版的两数运算完全不同,核心要解决的是运算符优先级和括号嵌套的问题。下面给你两种适合新手理解的实现思路:
方法一:后缀表达式(逆波兰表达式)转换法
这是经典的表达式求值方案,分两步走:把用户输入的中缀表达式(比如20/((10+5)*2))转换成后缀表达式,再计算后缀表达式的结果。
步骤1:中缀转后缀
遵循以下规则处理每个字符:
- 遇到数字直接加入输出列表
- 遇到运算符(+、-、*、/):
- 弹出栈中所有优先级大于等于当前运算符的运算符到输出列表,再把当前运算符压入栈
- 优先级规则:
*、/>+、-
- 遇到左括号
(:直接压入栈 - 遇到右括号
):弹出栈中运算符到输出列表,直到碰到左括号(,弹出左括号但不加入输出列表 - 遍历完所有字符后,把栈中剩余的运算符全部弹出到输出列表
以你的例子20/((10+5)*2)为例,转换后的后缀表达式是:20 10 5 + 2 * /
步骤2:计算后缀表达式
遍历后缀表达式,用栈处理:
- 遇到数字就压入栈
- 遇到运算符,弹出栈顶两个数(注意:后弹出的是左操作数),用运算符计算后把结果压回栈
- 遍历结束后,栈中剩余的唯一值就是计算结果
方法二:递归下降解析法
这种方法更贴近语法逻辑,把表达式按优先级拆分成不同的“语法单元”,用递归处理嵌套的括号,适合新手写代码实现。
核心思路
把表达式拆解为三个层级(优先级从低到高):
- 表达式(Expression):由多个项(Term)通过加减运算符连接而成
- 项(Term):由多个因子(Factor)通过乘除运算符连接而成
- 因子(Factor):要么是数字,要么是括号包裹的表达式(递归处理括号内的内容)
示例Java代码
import java.util.Scanner; public class AdvancedCalculator { private static Scanner scanner; private static int currentPos; private static String inputExpr; public static void main(String[] args) { scanner = new Scanner(System.in); System.out.println("请输入运算表达式:"); inputExpr = scanner.nextLine().replaceAll("\\s", ""); // 移除所有空格 currentPos = 0; try { double result = parseExpression(); System.out.println("计算结果:" + result); } catch (Exception e) { System.out.println("错误:" + e.getMessage()); } } // 处理加减运算(最低优先级) private static double parseExpression() { double result = parseTerm(); while (currentPos < inputExpr.length()) { char op = inputExpr.charAt(currentPos); if (op == '+' || op == '-') { currentPos++; double termValue = parseTerm(); if (op == '+') { result += termValue; } else { result -= termValue; } } else { break; } } return result; } // 处理乘除运算(中等优先级) private static double parseTerm() { double result = parseFactor(); while (currentPos < inputExpr.length()) { char op = inputExpr.charAt(currentPos); if (op == '*' || op == '/') { currentPos++; double factorValue = parseFactor(); if (op == '*') { result *= factorValue; } else { if (factorValue == 0) { throw new ArithmeticException("除数不能为0"); } result /= factorValue; } } else { break; } } return result; } // 处理数字和括号(最高优先级) private static double parseFactor() { char currentChar = inputExpr.charAt(currentPos); // 处理括号:递归解析括号内的表达式 if (currentChar == '(') { currentPos++; double result = parseExpression(); if (currentPos >= inputExpr.length() || inputExpr.charAt(currentPos) != ')') { throw new IllegalArgumentException("表达式缺少右括号"); } currentPos++; return result; } // 处理数字(支持小数) else if (Character.isDigit(currentChar) || currentChar == '.') { int startPos = currentPos; while (currentPos < inputExpr.length() && (Character.isDigit(inputExpr.charAt(currentPos)) || inputExpr.charAt(currentPos) == '.')) { currentPos++; } return Double.parseDouble(inputExpr.substring(startPos, currentPos)); } else { throw new IllegalArgumentException("无效字符:" + currentChar); } } }
代码说明
parseFactor遇到括号时,会递归调用parseExpression处理括号内的内容,自动解决嵌套括号的问题parseExpression依赖parseTerm,parseTerm依赖parseFactor,保证了乘除运算先于加减运算执行- 代码还处理了基本的错误情况:缺少括号、除数为0、无效字符
新手注意事项
- 先处理输入中的空格:用户输入可能带空格,要先移除或者忽略
- 错误处理:实际使用中要考虑各种非法输入(比如字母、不匹配的括号、除0)
- 扩展功能:如果要支持更多运算符(比如^幂运算),只需要调整优先级规则和对应的解析逻辑
内容的提问来源于stack exchange,提问作者Daleo dorito
相关产品推荐
相关产品推荐

