Android Studio Java中缀转后缀计算器输入小数点崩溃问题
问题说明
大学课程作业开发计算器应用,采用中缀转后缀(infix to postfix)规则实现计算逻辑,现有代码未适配小数点.的解析处理:输入包含小数点的表达式(例如1.1+)时程序会直接崩溃。经排查,运算符处理分支未覆盖小数点的相关处理逻辑,需要对应修复方案,也可提供更优的实现思路。
运行日志截图

现有实现代码
class Solution { public double calculate(String s) { if (s == null || s.length() < 1) return Integer.MIN_VALUE; return evalSuffix(inToSuffix(s)); } public int rank(Character op) { switch (op) { case '+': return 1; case '-': return 1; case '*': return 2; case '/': return 2; case '%': return 2; case '^': return 3; //可自行扩展更多运算符 default: return 0; //'('的优先级 } } public List<Object> inToSuffix(String s) { Stack<Character> opStack = new Stack<>(); List<Object> suffix = new LinkedList<>(); double num = 0; boolean numCached = false; char[] chars = s.toCharArray(); for (char c : chars) { if (Character.isDigit(c)) { num = num * 10 + (c - '0'); numCached = true; } else { if (numCached) { suffix.add(num); num = 0; numCached = false; } if (c == ' ' || c == '\t') continue; if (c == '(') opStack.push('('); else if (c == ')') { while (opStack.peek() != '(') suffix.add(opStack.pop()); //括号内运算符优先出栈 opStack.pop(); } else { while (!opStack.isEmpty() && rank(c) <= rank(opStack.peek())) suffix.add(opStack.pop()); opStack.push(c); } } } if (numCached) suffix.add(num); while (!opStack.isEmpty()) suffix.add(opStack.pop()); return suffix; } public double evalSuffix(List<Object> suffix) { Stack<Double> numStack = new Stack<>(); double num1 = 0; double num2 = 0; for (Object o : suffix) { if (o instanceof Character) { char op = (Character)o; num2 = numStack.pop(); num1 = numStack.pop(); switch (op) { case '+': numStack.push(num1 + num2); break; case '-': numStack.push(num1 - num2); break; case '*': numStack.push(num1 * num2); break; case '/': numStack.push(num1 / num2); break; case '%': numStack.push(num1 % num2); break; case '^': numStack.push((double)Math.pow((double)num1, (double)num2)); break; } } else numStack.push((Double) o); } return numStack.pop(); } }
修复方案
崩溃的核心原因是现有数字解析逻辑仅支持整数,遇到.会直接走运算符分支,既无法识别小数,也没有对应处理逻辑导致栈操作异常。修复只需要调整inToSuffix方法的数字解析部分,新增小数处理逻辑即可:
- 新增两个状态变量:
isDecimal:布尔值,标记当前是否正在解析小数部分decimalScale:小数位权重,初始为0.1,每解析一位小数就除以10
- 遍历到
.字符时做合法性校验:必须处于数字解析过程中、且当前数字还没出现过小数点,否则属于非法表达式;校验通过后标记isDecimal = true,初始化decimalScale = 0.1 - 解析数字字符时,判断当前是否处于小数模式:小数模式下累加值为
num += (c - '0') * decimalScale,之后decimalScale /= 10;整数模式沿用原有进位逻辑 - 每次数字入栈、重置解析状态时,同步重置
isDecimal和decimalScale的状态
修复后核心代码片段
仅展示修改后的inToSuffix方法,其余方法无需调整:
public List<Object> inToSuffix(String s) { Stack<Character> opStack = new Stack<>(); List<Object> suffix = new LinkedList<>(); double num = 0; boolean numCached = false; // 新增小数解析状态 boolean isDecimal = false; double decimalScale = 0.1; char[] chars = s.toCharArray(); for (char c : chars) { if (Character.isDigit(c)) { if (isDecimal) { // 小数部分累加 num += (c - '0') * decimalScale; decimalScale /= 10; } else { // 整数部分原有逻辑 num = num * 10 + (c - '0'); } numCached = true; } else if (c == '.') { // 处理小数点:校验合法性,标记小数解析状态 if (!numCached || isDecimal) { throw new IllegalArgumentException("非法的小数点位置"); } isDecimal = true; decimalScale = 0.1; } else { if (numCached) { suffix.add(num); // 重置所有数字解析状态 num = 0; numCached = false; isDecimal = false; decimalScale = 0.1; } if (c == ' ' || c == '\t') continue; if (c == '(') opStack.push('('); else if (c == ')') { while (opStack.peek() != '(') suffix.add(opStack.pop()); opStack.pop(); } else { while (!opStack.isEmpty() && rank(c) <= rank(opStack.peek())) suffix.add(opStack.pop()); opStack.push(c); } } } if (numCached) suffix.add(num); while (!opStack.isEmpty()) suffix.add(opStack.pop()); return suffix; }
额外优化建议
- 可以在方法入口新增表达式合法性校验,比如连续运算符、括号不匹配、首尾为运算符等场景提前抛出明确异常,避免运行时栈操作崩溃
- 做除法运算时新增除数为0的校验,返回明确错误提示
- 如果需要支持负数(比如
-1+2或者3*-2这类场景),可以额外补全负号作为一元运算符的处理逻辑
内容的提问来源于stack exchange,提问作者c.dipu0
相关产品推荐
相关产品推荐

