如果让你做一个计算器的算法,你可能觉得很简单。因为你认为的计算器是算1+1=2或2x3x4=24之类的,而计算机通常是有括号优先级的,比如(1+2)*3=9之类的,而且还是要输入括号求计算结果的,怎么办?优先级该怎么办?同时这也是一道面试题,今天就来看看这个算法吧~
这个算法看起来比较麻烦,但是都是有律可循的,涉及到堆栈方面的知识,也比较考验基础知识
import java.math.BigDecimal;
import java.util.Arrays;
import java.util.List;
import java.util.Stack;
/**
* 计算器
* @author RickSun && iFillDream
*/
public class Calculator3 {
//浮点精度
private static final int scale = 32;
//存储数字用的栈
private static Stack<BigDecimal> numberStack = null;
//存储运算符用的栈
private static Stack<Character> symbolStack = null;
//数字集合
private static final List numberList = Arrays.asList('0', '1', '2', '3', '4', '5', '6', '7', '8', '9','.');
//点
private static final Character dot = '.';
//参与运算的字符集
private static final List charList = Arrays.asList('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '-', '*', '/', '(', ')', '=', '.');
//二元运算符
private static final List symbolList = Arrays.asList('*', '/', '+', '-');
//非数字和点集合
private static final List nonumberdotList = Arrays.asList('*', '/', '+', '-','(',')');
public static void main(String[] args) {String str1 = " (1+2.0)*(3+4)";
String str2 = " (1.2.2+1)";
System.out.println(str1 + " = " + getResult(str1));
System.out.println(str2 + " = " + getResult(str2));
}
/**
* 计算结果
* @param expression 表达式
* @return
*/
public static BigDecimal getResult(String expression){
//1.校验字符串合法性
expression = check(expression);
if(expression.equals("")){
return new BigDecimal(0.0);
}
System.out.println("表达式正确");
//2.初始化栈
numberStack = new Stack<BigDecimal>();
symbolStack = new Stack<Character>();
numberStack.clear();
symbolStack.clear();
//3.计算结果
return js(expression);
}
/**
* 计算表达式
* @param expression 表达式
* @return
*/
private static BigDecimal js(String expression) {
//数字缓存
StringBuffer numberTemp = new StringBuffer();
// 从表达式的第一个字符开始处理
for (int i = 0; i < expression.length(); i++) {
char ch = expression.charAt(i); // 获取一个字符
if (numberList.contains(ch)) { // 若当前字符是数字
numberTemp.append(ch); // 加入到数字缓存中
} else { // 非数字的情况
String numberTempStr = numberTemp.toString(); // 将数字缓存转为字符串
if (!numberTempStr.isEmpty()) {
BigDecimal num = new BigDecimal(numberTempStr);
numberStack.push(num); // 将数字压栈
numberTemp = new StringBuffer(); // 重置数字缓存
}
// 判断运算符的优先级,若当前优先级低于栈顶的优先级,则先把计算前面计算出来
while (!checkLevel(ch) && !symbolStack.empty()) {
BigDecimal b = numberStack.pop(); // 出栈,取出数字,后进先出
BigDecimal a = numberStack.pop();
// 取出运算符进行相应运算,并把结果压栈进行下一次运算
switch ((char) symbolStack.pop()) {
case '+':
numberStack.push(a.add(b));
break;
case '-':
numberStack.push(a.subtract(b));
break;
case '*':
numberStack.push(a.multiply(b));
break;
case '/':
try {
if(b.equals(new BigDecimal(0))){
System.err.println("除数不能为0");
return new BigDecimal(0);
}
numberStack.push(a.divide(b));
} catch (java.lang.ArithmeticException e) {
// 进行除法出现无限循环小数时,就会抛异常,此处设置精度重新计算
numberStack.push(a.divide(b, scale,
BigDecimal.ROUND_HALF_EVEN));
}
break;
default:
break;
}
} // while循环结束
if (ch != '=') {
symbolStack.push(new Character(ch)); // 符号入栈
if (ch == ')') { // 去括号
symbolStack.pop();
symbolStack.pop();
}
}
}
} // for循环结束
return numberStack.pop(); // 返回计算结果
}
/**
* 比较优先级
* symbol比栈顶操作符优先级高则返回True,否则返回false
* @param symbol 操作符
* @return
*/
private static boolean checkLevel(char symbol) {
if (symbolStack.empty()) { // 空栈返回ture
return true;
}
/**
* 符号优先级说明(从高到低):
* 第1级: (
* 第2级: * /
* 第3级: + -
* 第4级: )
*/
char top = (char) symbolStack.peek(); // 查看堆栈顶部的对象,注意不是出栈
if (top == '(') {
return true;
}
// 比较优先级
switch (symbol) {
case '(': // 优先级最高
return true;
case '*': {
if (top == '+' || top == '-') // 优先级比+和-高
return true;
else
return false;
}
case '/': {
if (top == '+' || top == '-') // 优先级比+和-高
return true;
else
return false;
}
case '+':
return false;
case '-':
return false;
case ')': // 优先级最低
return false;
case '=': // 结束符
return false;
default:
break;
}
return true;
}
/**
* 检验表达式的合法性
* @param expression 表达式
* @return
*/
private static String check(String expression){
//1.判断是否为空
if(expression == null || expression.isEmpty() || expression.length() < 1){
System.err.println("表达式不能为空");
return "";
}
//2.去除空格
expression = expression != null ? expression.replaceAll(" ", "") : "";
//3.判断表达式尾部是否有"="号,没有则添加表示结束符
if (!"=".equals(expression.charAt(expression.length() - 1) + "")) {
expression += "=";
}
//4.判断表达式结构
Stack<Character> stack = new Stack<Character>();
int numberNum = 0;
int dotNum = 0;
boolean b = false; // 用来标记'='符号是否存在多个
for (int i = 0; i < expression.length(); i++) {
char n = expression.charAt(i);
// 判断字符是否合法
if(!charList.contains(n)){
System.err.println("表达式字符不合法,应为()0-9.*/+");
return "";
}
//判断重复点,点出现次数大于1则是错误
if(dot.charValue() == n ){
dotNum += 1; //等于点,点数+1
}else if(numberList.contains(n) && !dot.equals(n+"")){
numberNum +=1; //等于数字,数字+1
}else if(nonumberdotList.contains(n)){
//点数大于1 或 点数大于数字数且点数不能为0 时为不规范
if(dotNum > 1 || (dotNum >= numberNum && dotNum !=0) ){
System.err.println("表达式小数点重复或不规范!!");
return "";
}
dotNum = 0;
numberNum = 0;
}
// 将左括号压栈,用来给后面的右括号进行匹配
if ("(".equals(n + "")) {
stack.push(n);
}
if (")".equals(n + "")) { // 匹配括号
if (stack.isEmpty() || !"(".equals((char) stack.pop() + "")) { // 括号是否匹配
System.err.println("表达式缺少左括号");
return "";
}
}
// 检查是否有多个'='号
if ("=".equals(n + "")) {
if (b) {
System.err.println("表达式不能出现多等号");
return "";
}
b = true;
}
}
// 可能会有缺少右括号的情况
if (!stack.isEmpty()) {
System.err.println("表达式缺少右括号");
return "";
}
return expression;
}
}复制
运算结果如下:
此算法有以下缺点,如果你感兴趣可以看看怎么解决:
1、出现多个运算符时报错,例如:1++1
2、负数无法计算,例如:-1+2
复制
参考:https://www.cnblogs.com/wuqianling/p/5671667.html
【精彩推荐】
文章转载自笔记有云,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。
评论
相关阅读
Oracle 发布 Java 24
通讯员
146次阅读
2025-03-19 10:08:51
Oracle 正式发布 Java 24
千钧
108次阅读
2025-03-20 11:26:28
Java 开发玩转 MCP:从 Claude 自动化到 Spring AI Alibaba 生态整合
阿里巴巴中间件
42次阅读
2025-04-08 11:01:30
Java 与 Oracle 集成
芃芃
41次阅读
2025-03-19 21:21:38
从零玩转GaussDB:Java开发者必学的JDBC操作指南
数据库运维之道
31次阅读
2025-03-19 11:20:48
java项目选择云服务器怎么选?
云知识CLOUD
25次阅读
2025-04-09 20:02:37
Java反射大揭秘:程序员的“偷窥”与“开挂”指南
让天下没有难学的编程
15次阅读
2025-03-28 15:02:40
瞧瞧别人家的判空,那叫一个优雅!
jinchanchanwaji
14次阅读
2025-04-03 14:56:21
【JVM祖传手艺大揭秘】双亲委派:Java世界的"啃老"生存法则
让天下没有难学的编程
9次阅读
2025-04-09 11:01:12
Java反射大揭秘:程序员的“偷窥”与“开挂”指南
让天下没有难学的编程
9次阅读
2025-03-23 22:09:15