1、中缀表达式转后缀表达式
中缀表达式为我们人类能识别的方式,而后缀表达式是计算机进行运算的方式。
转换规则
1)我们使用一个stack栈结构存储操作符,用一个List结构存储后缀表达式结果
2)首先读取到数字,直接存入list中
3)当读取到左括号"("时,直接压栈,当读取到运算符时,分两种情况讨论
a.当运算符栈为空或者栈顶操作符的优先级小于当前运算符优先级时(如+和-的优先级低于 * 和 /),直接入栈
b.当运算符不为空时且栈顶操作符的优先级大于或等于当前运算符优先级时,循环执行出栈操作并加入list中,直到遇到优先级小于当前运算符的元素为止。循环执行完后再将当前运算符压栈。另外需要注意的是,只有遇到右括号时,左括号才出栈
4) 当遇到右括号")"时,循环执行出栈操作并加入到list中,直到遇到左括号为止。并将左括号弹出,但不加入list中
5) 表达式的值读取完后,将操作符栈中的所有元素弹出并加入到list中
执行完上面步骤后,list中存储的顺序即为我们转换后的后缀表达式的结果
动态展示
https://www.bilibili.com/video/BV1xp4y1r7rc?spm_id_from=333.880.my_history.page.click
2、后缀表达式计算结果
转换规则
1)我们使用一个stack栈结构存储数字
2)遍历后缀表达式,
a)读取到数字,直接压栈
b)读取到运算符,依次取出栈顶的元素(取两次),用该运算符进行运算,并将运算结果重新压栈。
3)遍历结束,栈只剩下一个元素,即计算结果
动态展示
https://www.bilibili.com/video/BV1iz4y1k7Ct?spm_id_from=333.880.my_history.page.click
3、Java实现
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;
public class Solution {
public static void main(String[] args) {
String expression ="1+((22+33)*4/11)-5";
//将expression转为List,便于后续运算
List<String> expressionList = expressionToList(expression);
System.out.println(expressionList);
//将中缀表达式转换为后缀表达式
List<String> suffixList = parseToSuffixExpression(expressionList);
System.out.println(suffixList);
//后缀表达式计算结果
int calculate = calculate(suffixList);
System.out.println(calculate);
}
/**
* 根据后缀表达式list计算结果
* @param list
* @return
*/
private static int calculate(List<String> list) {
Stack<Integer> stack = new Stack<>();
for(int i=0; i<list.size(); i++){
String item = list.get(i);
if(item.matches("\\d+")){
//是数字
stack.push(Integer.parseInt(item));
}else {
//是操作符,取出栈顶两个元素
int num2 = stack.pop();
int num1 = stack.pop();
int res = 0;
if(item.equals("+")){
res = num1 + num2;
}else if(item.equals("-")){
res = num1 - num2;
}else if(item.equals("*")){
res = num1 * num2;
}else if(item.equals("/")){
res = num1 / num2;
}else {
throw new RuntimeException("运算符错误!");
}
stack.push(res);
}
}
return stack.pop();
}
//将中缀表达式List<String>集合转为后缀表达式List<String>集合
public static List<String> parseToSuffixExpression(List<String> expressionList) {
//创建一个栈用于保存运算符
Stack<String> opStack = new Stack<>();
//创建一个list用于保存后缀表达式
List<String> suffixList = new ArrayList<>();
for (String item : expressionList) {
//item是操作符
if (isOperator(item)){
//栈为空 或者 栈顶元素为左括号 或者 当前操作符大于栈顶操作符直接压栈
if (opStack.isEmpty() || "(".equals(opStack.peek()) || priority(item)>priority(opStack.peek())){
opStack.push(item);
}else {
//否则将栈中元素出栈入list,直到遇到大于当前操作符或者遇到左括号时
while (!opStack.isEmpty() && !"(".equals(opStack.peek()) && priority(item) <= priority(opStack.peek())){
//当前操作符小于栈顶操作符
suffixList.add(opStack.pop());
}
//当前操作符压栈
opStack.push(item);
}
}else if(isNumber(item)){
//item是数字则直接入list
suffixList.add(item);
}else if("(".equals(item)){
//item是左括号,压栈
opStack.push(item);
}else if(")".equals(item)){
//是右括号 ,将栈中元素弹出入队,直到遇到左括号,左括号出栈,但不入队
while (!opStack.isEmpty()){
if("(".equals(opStack.peek())){
opStack.pop();
break;
}else {
suffixList.add(opStack.pop());
}
}
}else {
throw new RuntimeException("有非法字符!");
}
//item是右括号
}
//循环完毕,如果操作符栈中元素不为空,将栈中元素出栈入队
while (!opStack.isEmpty()){
suffixList.add(opStack.pop());
}
return suffixList;
}
//判断字符串是否为操作符
public static boolean isOperator(String op){
return op.equals("+") || op.equals("-") || op.equals("*") || op.equals("/");
}
//获取操作符优先级
public static int priority(String op){
if(op.equals("*") || op.equals("/")){
return 1;
}else if(op.equals("+") || op.equals("-")){
return 0;
}
return -1;
}
//判断字符串是否为数字
public static boolean isNumber(String num){
return num.matches("^\\d+$");
}
//将输入的原中缀表达式字符串转为list<String>集合
public static List<String> expressionToList(String expression){
List<String> list = new ArrayList<>();
for (int i = 0; i <expression.length() ; ) {
char ch = expression.charAt(i);
//ascii:48-57 表示数字0-9
if (ch<48 || ch>57){
//是操作符
list.add(ch+"");
i++;
}else {
//是数字
String str ="";
while (i<expression.length() && expression.charAt(i)>=48
&& expression.charAt(i)<=57){
str+=expression.charAt(i);
i++;
}
list.add(str);
}
}
return list;
}
}