/**
* 后缀表达式实现计算器
*/
public class SuffixExpressionCalculator {
/**
* 计算方法
*
* @param infixExpr 中缀表达式
* @return 结果
*/
public int calculate(String infixExpr) {
Stack<Integer> stack = new Stack<>();
List<String> suffixExprList = infixToSuffix(infixExpr);
System.out.println("后缀表达式: " + suffixExprList);
for (String str : suffixExprList) {
char ch = str.charAt(0);
if (!isOperator(ch)) {
//stack.push((int) ch); 这里出问题, 举个例子: 本来应该是数字类型的5, 现在是char类型的 '5' 转换成int之后是53,肯定就不对了
stack.push(Integer.parseInt(str));
} else {
int num1 = stack.pop();
int num2 = stack.pop();
stack.push(operate(num1, num2, ch));
}
}
return stack.pop();
}
/**
* 加减乘除四则运算
*
* @param num1 值1
* @param num2 值2
* @param operator 操作符
* @return 结果
*/
private int operate(int num1, int num2, char operator) {
int result = 0;
switch (operator) {
case '+':
result = num1 + num2;
break;
case '-':
result = num2 - num1;
break;
case '*':
result = num1 * num2;
break;
case '/':
result = num2 / num1;
break;
}
return result;
}
/**
* 中缀转后缀
*
* @param infixExpr 中缀表达式
* @return 后缀表达式
*/
private List<String> infixToSuffix(String infixExpr) {
// Stack<Integer> stackNum = new Stack<>(); 这里出现问题:如果泛型都是Integer那最终结果输出的字符char也会转为int, 导致无法分辨出数字和符号
// Stack<Integer> stackOpe = new Stack<>();
Stack<String> stackNum = new Stack<>();
Stack<String> stackOpe = new Stack<>();
int len = infixExpr.length();
for (int i = 0; i < len; ) {
char ch = infixExpr.charAt(i);
String chStr = String.valueOf(ch);
// 判断是否是操作符
if (isOperator(ch)) { // 是操作符
if (stackOpe.empty()) { // 是操作符且栈为空,则符号直接入栈
stackOpe.push(chStr);
} else { // 如果符号栈不为空
char top = stackOpe.peek().charAt(0);
// 判断当前符号与栈顶符号的优先级
if (priority(ch) <= priority(top)) { // 当前符号优先级小于等于栈顶符号
if (top != '(') { // 栈顶符号不是左括号
stackNum.push(stackOpe.pop()); // 此时, 将栈顶符号取出压入数字栈
}
stackOpe.push(chStr); // 再将当前符号压入符号栈, 这里还包含一种情况是如果top=='(',则符号直接入栈
} else { // 当前符号优先级大于栈顶符号
if (ch == ')') { // 当前符号是右括号, 需要依次弹出栈中符号压入数字栈,直到左括号为止, 注意: 左括号也需要弹出,但是不入数字栈
while (true) {
String cha = stackOpe.pop();
if (cha.charAt(0) == '(') {
//stackOpe.pop(); 这里出现问题: 多取了一次
break;
}
stackNum.push(cha);
}
} else { // 当前符号不是右括号, 且当前符号优先级大于栈顶符号, 则当前符号直接入栈
stackOpe.push(chStr);
}
}
}
i++; // 循环 + 1
} else { // 字符是数字
StringBuilder sb = new StringBuilder();
sb.append(ch);
// 数字有可能不是个位数, 有可能是多位数, 所以按照char遍历就会出问题, 这里while循环就是处理这种情况
while (true) {
i++; // 循环 + 1
if (i == len) { // 处理多位数在表达式最后的情况, 如果等于了表达式的长度就退出
break;
}
char cha = infixExpr.charAt(i);
if (isOperator(cha)) { // 处理多位数在表达式中间的情况, 如果是操作符就退出
break;
}
sb.append(cha);
}
// 把得到的数字压入数字栈
stackNum.push(sb.toString());
}
}
while (!stackOpe.isEmpty()) {
stackNum.push(stackOpe.pop());
}
List<String> list = new ArrayList<>();
List<String> listData = new ArrayList<>();
while (!stackNum.isEmpty()) {
list.add(stackNum.pop());
}
// 转为逆序(逆波兰)
for (int i = list.size() - 1; i > -1; i--) {
listData.add(list.get(i));
}
return listData;
}
private boolean isOperator(char ch) {
return ch == '+' || ch == '-' || ch == '*' || ch == '/' || ch == '(' || ch == ')';
}
private int priority(char ch) {
if (ch == '+' || ch == '-') {
return 0;
}
if (ch == '*' || ch == '/') {
return 1;
}
if (ch == '(' || ch == ')') {
return 2;
}
return -1;
}
public static void main(String[] args) {
SuffixExpressionCalculator sec = new SuffixExpressionCalculator();
System.out.println(sec.calculate("5*(3+4)-6+80"));
}
}
打印结果:
后缀表达式: [5, 3, 4, +, *, 6, -, 80, +]
109
之前的博客中已经把思路写出来了,这篇博客用代码来实现一下,也算自己的学习笔记。祝大家周末愉快~~~