中缀表达式转后缀表达式(逆波兰表达式) java详细讲解
中缀表达式转后缀表达式(逆波兰表达式) java详细讲解
为什么需要转换
大家看到,后缀表达式适合计算式进行运算,但是人却不太容易写出来,尤其是表达式很长的情况下,因此在开发中,我们需要将 中缀表达式转成后缀表达式。
具体的步骤
- 初始化两个栈:运算符栈s1和储存中间结果的栈s2;
- 从左至右扫描中缀表达式;
- 遇到操作数时,将其压s2;
- 遇到运算符时,比较其与s1栈顶运算符的优先级:
1.如果s1为空,或栈顶运算符为左括号“(”,则直接将此运算符入栈;
2.否则,若优先级比栈顶运算符的高,也将运算符压入s1;
3.否则,将s1栈顶的运算符弹出并压入到s2中,再次转到(4.1)与s1中新的栈顶运算符相比较; - 遇到括号时:
(1) 如果是左括号“(”,则直接压入s1
(2) 如果是右括号“)”,则依次弹出s1栈顶的运算符,并压入s2,直到遇到左括号为止,此时将这一对括号丢弃 - 重复步骤2至5,直到表达式的最右边
- 将s1中剩余的运算符依次弹出并压入s2
- 依次弹出s2中的元素并输出,结果的逆序即为中缀表达式对应的后缀表达式
举例说明
将中缀表达式“1+((2+3)×4)-5”转换为后缀表达式的过程如下,因此结果为 “1 2 3 + 4 × + 5 –”
解题思路
代码实现
package com.qf.stack;import java.util.ArrayList;import java.util.List;import java.util.Stack;public class PolandNation { public static void main(String[] args) { //(55+6)*2+33-12 String expression="(55+6)*2+33-12"; List<String> splitList = getSplitList(expression); List<String> sufferList = getSufferList(splitList); int cal = cal(sufferList); System.out.println("计算得到的结果:"+cal); } public static List<String> getStringList(String express){ String[] split = express.split(" "); List<String> list=new ArrayList<>(); for (String s : split) { list.add(s); } return list; } /*从左至右扫描表达式,遇到数字时,将数字压入堆栈,遇到运算符时,弹出栈顶的两个数, 用运算符对它们做相应的计算(次顶元素 和 栈顶元素),并将结果入栈; 重复上述过程直到表达式最右端,最后运算得出的值即为表达式的结果 */ public static int cal(List<String> list){ Stack<String> stack=new Stack<>(); for (String item : list) { if (item.matches("\\d+")){ stack.push(item); }else{ int num1 = Integer.parseInt(stack.pop()); int num2 = Integer.parseInt(stack.pop()); int res=0; switch (item){ case "+": res=num1+num2; break; case "-": res=num2-num1; break; case "*": res=num1*num2; break; case "/": res=num2/num1; break; default: break; } stack.push(""+res); } } int res=Integer.parseInt(stack.pop()); return res; } //获取中缀表达式的拆分 public static List<String> getSplitList(String express){ List<String> list=new ArrayList<>(); int i=0; String str; do { if (express.charAt(i)>57||express.charAt(i)<48){ list.add(String.valueOf(express.charAt(i))); i++; }else{ str=""; while (i<express.length()&&express.charAt(i)<=57&&express.charAt(i)>=48){ str=str+express.charAt(i); i++; } list.add(str); } }while (i<express.length()); return list; } //1 + ( ( 2 + 3 )× 4) - 5 //把中缀表达式转换为后缀表达式 /* 1) 初始化两个栈:运算符栈s1和储存中间结果的栈s2; 2) 从左至右扫描中缀表达式; 3) 遇到操作数时,将其压s2; 4) 遇到运算符时,比较其与s1栈顶运算符的优先级: 1.如果s1为空,或栈顶运算符为左括号“(”,则直接将此运算符入栈; 2.否则,若优先级比栈顶运算符的高,也将运算符压入s1; 3.否则,将s1栈顶的运算符弹出并压入到s2中,再次转到(4.1)与s1中新的栈顶运算符相比较; 5) 遇到括号时: (1) 如果是左括号“(”,则直接压入s1 (2) 如果是右括号“)”,则依次弹出s1栈顶的运算符,并压入s2,直到遇到左括号为止,此时将这一对括号丢弃 6) 重复步骤2至5,直到表达式的最右边 7) 将s1中剩余的运算符依次弹出并压入s2 8) 依次弹出s2中的元素并输出,结果的逆序即为中缀表达式对应的后缀表达式*/ public static List<String> getSufferList(List<String> list){ //运算符栈s1 Stack<String> operateStack=new Stack<>(); //中间结果 使用ArrayList的原因是因为可以减少后缀表达式的逆序 List<String> tempList=new ArrayList<>(); for (String item : list) { if (item.matches("\\d+")){ tempList.add(item); } else if (item.equals("(")){ operateStack.push(item); }else if (item.equals(")")){ while(!operateStack.peek().equals("(")){ tempList.add(operateStack.pop()); } operateStack.pop(); }else{ while(operateStack.size()!=0&&Operation.getPrior(item)<=Operation.getPrior(operateStack.peek())){ tempList.add(operateStack.pop()); } operateStack.push(item); } } while (operateStack.size()!=0){ tempList.add(operateStack.pop()); } return tempList; }}class Operation{ public static final int DEV=2; public static final int MUL=2; public static final int DEC=1; public static final int ADD=1; public static int getPrior(String rex){ int res=0; switch (rex){ case "+": res=ADD; break; case "-": res=DEC; break; case "*": res=MUL; break; case "/": res=DEV; break; default: System.out.println("未匹配字符"); break; } return res; }}