- * + 3 4 5 6
转换方法:运算符根据运算级别从右到左排,操作数根据运算级别从左到右排列,比如上面的表达式:运算级别顺序为+、*、-,从右到左排:- * +;操作数顺序为3、4、5、6,从左到右排:3 4 5 6 。组合就是:- * + 3 4 5 6。
图解前缀表达式求值:
二、中缀表达式定义:运算符位于与其相关的操作数之间,我们常见的即为中缀表达式
运算:需要两个栈,一个为数栈存放数字,另一个为符号栈存放操作符。
1.通过一个index值(索引),来遍历表达式;2.如果发现是一个数字,就直接入数栈;3.如果发现扫描到的是一个符号,分如下情况: 3.1如果发现当前的符号栈为空,直接入栈; 3.2如果符号栈有操作符,就进行比较,如果当前的操作符的优先级小于或等于栈中的操作符,就需要从数栈中pop出两个数(这里注意如果是减法和除法,次顶元素作为被减数或被除数,与前缀表达式相反),再从符号栈中pop出一个符号,进行运算,将得到的结果入数栈,然后操作符入符号栈;如果当前的操作符的优先级大于栈中的操作符,就直接入符号栈。4.当表达式扫描完毕,就顺序从数栈中和符号栈中pop出相应的数和符号,并运算。5.最后在数栈只有一个数字,就是表达式的结
图解参考:图解用栈实现中缀表达式求值
三、后缀表达式定义:运算符位于与其相关的操作数之后
运算:
1.扫描表达式,如果是数直接入栈;2.如果是运算符,从栈中弹出两个数进行运算,然后将结果入栈;3.最后栈中剩余的一个值即为表达式的值
如:(3+4)*5-6 的后缀表达式为:
3 4 + 5 * 6 -
四、中缀表达式转后缀表达式
步骤分析
1.初始化两个栈:运算符栈s1和中间结果栈s2;2.从左到右扫描中缀表达式;3.遇到操作数时,将其压入s2;4.遇到运算符时,比较其与s1栈顶运算符的优先级;4.1.如果s1为空,或运算符栈顶为左括号“(”,则直接将此运算符入栈;4.2.否则,若优先级比栈顶运算符的高,也将运算符压入s1(注意必须是高,等于或低于都不行) 4.3.否则,将s1栈顶的运算符弹出并压入s2中,再次转到4.1与s1中新的栈顶运算符进行比较;5.遇到括号时:5.1.如果是左括号“(”,则直接压入s1;5.2.如果是右括号“)”,则依次弹出s1栈顶的运算符,并压入s2,直到遇到左括号为止,此时将这一对括号丢弃;6.重复步骤2-5,直到表达式的最右边;7.将s1中剩余的运算符依次弹出并压入s2;8.依次弹出s2中的元素并输出,结果的逆序即为中缀表达式对应的后缀表达式
图解步骤如下:
①扫描到前7个字符时,依次入栈,如下图:(如果栈顶为左括号,下一个运算符直接入栈)
②当扫描到右括号“)”时,依次弹出s1栈顶的运算符压入s2,直到遇到左括号,一对括号消除;
③然后扫描到‘*’直接入s1,扫描到‘4’直接入s2
④接着扫描到第二个右括号‘)’,将s1栈顶的‘*’弹出压入s2,然后消除一对括号
⑤接着扫描到‘-’,优先级和s1栈顶的‘+’相同,把s1栈顶运算符弹出压入s2,然后将‘-’压入s1,最后扫描到的‘5’入s2栈
⑥最后将s1中的运算符依次弹出并压入s2
⑦依次弹出s2中的元素并输出,结果的逆序即为中缀表达式对应的后缀表达式
s2弹出顺序:- 5 + * 4 + 3 2 1 逆序,即后缀表达式:1 2 3 + 4 * + 5 -
代码实现
思路:
先将中缀表达式转换成对应的ArrayList集合,便于遍历,如上述表达式:"1+((2+3)*4)-5" 转换后应该为:[1, +, (, (, 2, +, 3, ), *, 4, ), -, 5]
将步骤①得到的List转成后缀表达式对应的List,如[1, +, (, (, 2, +, 3, ), *, 4, ), -, 5] 转换为[1, 2, 3, +, 4, *, +, 5, -]
public static List infixExpression2List(String infixExpression) { ArrayList ls = new ArrayList(); int i = 0; String str;//对多位数进行拼接 char ch;//每遍历到一个字符,就放入ch do { //如果ch是一个非数字,加入ls if ((ch = infixExpression.charAt(i)) < 48 || (ch = infixExpression.charAt(i)) > 57) { ls.add("" + ch); i++; } else { str = "";//先将str置空 //这里判断i的范围是因为内层循环结束后才会判断外层循环条件,如果不加会在内层循环时出现下标越界 while (i < infixExpression.length() && (ch = infixExpression.charAt(i)) >= 48 && (ch = infixExpression.charAt(i)) <= 57) { str += ch;//拼接多位数 i++; } ls.add(str); } } while (i < infixExpression.length()); return ls;}
②比较运算符优先级的方法
class Operation { private static int ADD = 1; private static int SUB = 1; private static int MUL = 2; private static int DIV = 2; public static int getValue(String operation) { int result = 0; switch (operation) { case "+": result = ADD; break; case "-": result = SUB; break; case "*": result = MUL; break; case "/": result = DIV; break; default: System.out.println("不存在的运算符"); break; } return result; }}
③将步骤①得到的List转成后缀表达式对应的List
public static Listinfix2SuffixExpressionList(List infixList) { Stack s1 = new Stack();//操作符栈 //由于在整个转换过程中s2栈都没有pop操作,而且后面需要逆序输出,为了简化,可以不用栈结构,改用List s2代替 List s2 = new ArrayList(); //遍历infixList for (String item : infixList) { //如果是一个数,则入s2 if (item.matches("\\d+")) { s2.add(item); } else if (item.equals("(")) {//如果是左括号,直接入s1栈 s1.push(item); } else if (item.equals(")")) {//如果是右括号,则依次弹出s1栈顶的运算符,并加入s2,直到遇到左括号为止,此时将这一对括号丢弃; while (!s1.peek().equals("(")) { s2.add(s1.pop()); } s1.pop();//去除s1中对应的左括号,很重要!!! } else { //如果是运算符,比较其与s1栈顶运算符的优先级: //1.如果s1为空,或运算符栈顶为左括号“(”,则直接将此运算符入栈; //2.否则,若优先级比栈顶运算符的高,也将运算符压入s1(注意必须是高,等于或低于都不行) //3.否则,将s1栈顶的运算符弹出并压入s2中,再次转到4.1与s1中新的栈顶运算符进行比较; //当item的优先级小于等于s1栈顶的优先级时,将s1栈顶的运算符弹出并加入s2中,再次转到1与s1中新的栈顶运算符进行比较 while (s1.size() != 0 && Operation.getValue(s1.peek()) >= Operation.getValue(item)) { s2.add(s1.pop()); } //将item入栈s1 s1.push(item); } } //将s1中的剩余运算符弹出并加入s2 while (s1.size() != 0) { s2.add(s1.pop()); } return s2;//由于加入的是一个List,本身有序,所以正常输出即为后缀表达式而不必逆序}
④通过步骤③得到的list计算后缀表达式的值
public static int calculator(List ls){ Stackstack = new Stack(); //遍历ls for (String item : ls) { if (item.matches("\\d+")){//如果是数直接入栈 stack.push(item); }else{ int num2=Integer.parseInt(stack.pop()); int num1=Integer.parseInt(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 Integer.parseInt(stack.pop());}
图解后缀表达式求值