中缀表达式计算,注释完整易懂。无健壮性,要求正确输入。
import java.util.Scanner;
import java.util.Stack;
public class Main {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
String expression = input.nextLine();
try {
System.out.println(expression + " = " + calculateInfixExpression(expression));
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
//计算中缀表达式
public static int calculateInfixExpression(String expression) {
//定义两个栈(操作数栈、运算符栈)
Stack<String> s1 = new Stack<String>();
Stack<String> s2 = new Stack<String>();
//遍历表达式
int flag = 0;//上一个是空或者符号则为0
int isNegative = 0;//是一就把数字变负数
int i = 0;
int len = expression.length();
char ch; //当前字符
String op; //运算符
int num1; //操作数1
int num2; //操作数2
int res; //运算结果
while (i < len) {
ch = expression.charAt(i);
//判断当前字符是操作数还是运算符
//System.out.println(ch);
if (ch >= 48 && ch <= 57) {
//当前字符是操作数,则直接入栈
String str = "" + ch;
while (i + 1 < len) {
ch = expression.charAt(i + 1);
if (ch < 48 || ch > 57) {
break;
} else {
i++;
str += ch;
}
}
if (isNegative == 1) {
str = "-" + str;
isNegative = 0;
}
s1.push(str);
flag = 1;
} else {
//当前字符是运算符,则判断是 左括号 或 右括号 或 + - * /
if (ch == '(') {
//直接入栈
s2.push("" + ch);
flag = 0;
} else if (ch == ')') {
//出栈并运算,直到遇到左括号,最后丢弃这对括号
while (!s2.peek().equals("(")) {
op = s2.pop();
num1 = Integer.parseInt(s1.pop());
num2 = Integer.parseInt(s1.pop());
//计算 num2 op num1 并将结果压入栈, 注意传参的顺序
res = calculate(num2, op, num1);
s1.push("" + res);
}
//丢弃这对括号
s2.pop();
} else if (ch == '-') {
if (flag == 0) {
isNegative = 1;
} else {
if (s2.empty()) {
s2.push("" + ch);
} else {
//判断优先级
String currentOp = "" + ch;
String stackTopOp = s2.peek();
//当前运算符 > 栈顶运算符,直接入栈
if (priority(currentOp) > priority(stackTopOp)) {
s2.push(currentOp);
} else {
//当前运算符 <= 栈顶运算符,不断弹出栈顶运算符并计算,直到当前 运算符 >栈顶运算符 或 栈为空
while (!s2.empty() && priority(currentOp) <= priority(s2.peek())) {
op = s2.pop();
num1 = Integer.parseInt(s1.pop());
num2 = Integer.parseInt(s1.pop());
res = calculate(num2, op, num1);
s1.push("" + res);
}
//将当前运算符压入栈
s2.push(currentOp);
}
}
flag = 0;
}
} else if (isOper(ch)) {
//如果是 + - * /, 则需要跟栈顶运算符判断优先级(先判断栈是否为空,为空就直接入栈)
if (s2.empty()) {
s2.push("" + ch);
} else {
//判断优先级
String currentOp = "" + ch;
String stackTopOp = s2.peek();
//当前运算符 > 栈顶运算符,直接入栈
if (priority(currentOp) > priority(stackTopOp)) {
s2.push(currentOp);
} else {
//当前运算符 <= 栈顶运算符,不断弹出栈顶运算符并计算,直到当前 运算符 >栈顶运算符 或 栈为空
while (!s2.empty() && priority(currentOp) <= priority(s2.peek())) {
op = s2.pop();
num1 = Integer.parseInt(s1.pop());
num2 = Integer.parseInt(s1.pop());
res = calculate(num2, op, num1);
s1.push("" + res);
}
//将当前运算符压入栈
s2.push(currentOp);
}
}
flag = 0;
} else {
//遇到无法识别字符则抛出异常
throw new RuntimeException("无法识别" + ch);
}
}
i++;
}
//将剩下的操作符逐一弹出栈并计算
while (!s2.empty()) {
op = s2.pop();
num1 = Integer.parseInt(s1.pop());
num2 = Integer.parseInt(s1.pop());
res = calculate(num2, op, num1);
s1.push("" + res);
}
res = Integer.parseInt(s1.pop());
return res;
}
//判断是不是运算符
public static boolean isOper(char op) {//这里不对减号进行判断,因为减号可能是负号,计算时单独判断
return op == '+' || op == '%' || op == '*' || op == '/';
}
//计算 num1 op num2
public static int calculate(int num1, String op, int num2) {
int res = 0;
switch (op) {
case "+":
res = num1 + num2;
break;
case "-":
res = num1 - num2;
break;
case "*":
res = num1 * num2;
break;
case "/":
res = num1 / num2;
break;
case "%":
res = num1 % num2;
break;
default:
break;
}
return res;
}
//返回运算符的优先级
public static int priority(String op) {
switch (op) {
case "+":
case "-":
return 1;
case "*":
case "/":
case "%":
return 2;
case "(":
return 0;
default:
return -1;
}
}
}