逆波兰表达式又称作后缀表达式,在四则混合运算的程序设计中用到。
例如:
1+2写成后缀表达式就是12+
4+5*(3-2)的后缀表达式就是4532-*+
后缀表达式在四则运算中带来了意想不到的方便,在生成过程中自动保持了优先级;
生成逆波兰表达式的算法如下:
我们首先的用两个栈结构来存储运算符和操作数,在java中有Stack类可以用;
从做到右遍历我们输入的中缀表达式:
1、如果是操作数的话,那么就直接压入存放操作数的堆栈;
2、如果是"("左括号的话,那么就直接压入存放运算符的堆栈;
3、如果是")"右括号的话,那么就从运算符堆栈中弹数据,并将弹出的数据压入到操作数堆栈中,直到遇到"("为止,这里值得注意的是,"("是必须要从运算符堆栈中弹出的,但是不压入到操作数堆栈,后缀表达式中是不包含括号的;
4、如果是其他符号,就是其他的运算符+-*/这些,那么就:
a、如果运算符堆栈为空,则直接压入运算符堆栈;
b、如果不为空且此时运算符堆栈的栈顶元素为括号,包括左括号和右括号,那么也是直接压入运算符堆栈中;
c、如果此时遍历到的元素的优先级比此时运算符堆栈栈顶元素的优先级高,则直接压入运算符堆栈;
d、如果正在遍历的元素的优先级和运算符堆栈栈顶的元素的优先级相等或者更小,则需要将栈顶元素弹出并且放到操作数堆栈 中,并且将正在遍历的元素压入到运算符堆栈,其实运算符堆栈中的元素顺序就是优先级的顺序;
5、直到遍历完表达式,此时还需要将运算符堆栈中的所有元素压入到操作数堆栈中,算法完成。
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
根据以上算法可以得到逆波兰表达式,我们得到逆波兰表达式之后,必须求得正确的计算结果,有了逆波兰表达式,计算起来就攘夷多了,算法如下:
用另一个堆栈来保存数据,从左到右遍历逆波兰表达式:
1、如果是数字,则直接压入堆栈中;
2、如果是运算符(+,-,*,/),则弹出堆栈中的两个数据,进行相应的计算,计算完成之后得到一个数据,然后又压入堆栈中;
3、知道遍历完成,此时堆栈中的数据就是最后计算的结果,简单吧。
根据以上算法,博主写了相应的java代码,值得大家注意的是,在本程序中,并不包含对表达式合法性的判断,博主想用正则表达式去判断一个表达式的合法性,但是想了很久没有搞定,如果有大神搞定的,tell tell我,感激不尽。。。
import java.util.ArrayList; import java.util.Scanner; import java.util.Stack; public class Main { public static void main(String[] args) { Scanner sc = new Scanner(System.in); String str1 = sc.nextLine(); //存放运算符的堆栈 Stack<String> operatorStack = new Stack<String>(); //存放元素的堆栈 Stack<String> elementStack = new Stack<String>(); ArrayList<String> strList = new ArrayList<String>(); String str2 = ""; int flag = 0; for (int i = 0; i < str1.length();i++) if (Character.isDigit(str1.charAt(i))){ flag = 0; str2 += String.valueOf(str1.charAt(i)); if (i == str1.length() - 1) strList.add(str2); } else{ if (flag == 0){ strList.add(str2); str2 = ""; flag = 1; } strList.add(String.valueOf(str1.charAt(i))); } //System.out.println(strList); //遍历strList集合,生成逆波兰表达式的过程 for (String s:strList){ if (Character.isDigit(s.charAt(0))) elementStack.push(s); else if (s.equals("(")) operatorStack.push(s); else if (s.equals(")")){ String temp = ""; do{ temp = operatorStack.pop(); if (!temp.equals("(")) elementStack.push(temp); } while(!temp.equals("(")); } else{ if (operatorStack.empty()) operatorStack.push(s); else if (operatorStack.peek().equals("(") || operatorStack.peek().equals(")")) operatorStack.push(s); else if (priorty(s,operatorStack.peek())) operatorStack.push(s); else{ elementStack.push(operatorStack.pop()); operatorStack.push(s); } } } while (!operatorStack.empty()){ elementStack.push(operatorStack.pop()); } ArrayList<String> str2List = new ArrayList<String>(); Stack<String> swapStack = new Stack<String>(); while(!elementStack.empty()){ swapStack.push(elementStack.pop()); } while (!swapStack.empty()){ str2List.add(swapStack.pop()); } System.out.println(str2List); //根据逆波兰表达式计算出结果 Stack<String> st1 = new Stack<String>(); for (String s:str2List){ if (Character.isDigit(s.charAt(0))){ st1.push(s); } else if (s.equals("+")){ String left = st1.pop(); String right = st1.pop(); Integer jieguo = Integer.valueOf(left) + Integer.valueOf(right); st1.push(Integer.toString(jieguo)); } else if (s.equals("-")){ String left = st1.pop(); String right = st1.pop(); Integer jieguo = Integer.valueOf(right) - Integer.valueOf(left); st1.push(Integer.toString(jieguo)); } else if (s.equals("*")){ String left = st1.pop(); String right = st1.pop(); Integer jieguo = Integer.valueOf(right) * Integer.valueOf(left); st1.push(Integer.toString(jieguo)); } else if (s.equals("/")){ String left = st1.pop(); String right = st1.pop(); Integer jieguo = Integer.valueOf(right) / Integer.valueOf(left); st1.push(Integer.toString(jieguo)); } else System.exit(-1); } String ss = st1.pop(); System.out.println(ss); System.out.println("true"); } /*运算符优先级判定*/ public static boolean priorty(String str1,String str2){ if ((str1.equals("*") || str1.equals("/")) &&(str2.equals("+") || str2.equals("-"))) return true; else if (str1.equals(str2)) return false; else if ((str1.equals("+") || str1.equals("-")) && ((str2.equals("+") || str2.equals("-")))) return false; else if ((str1.equals("*") || str1.equals("/")) && ((str2.equals("*") || str2.equals("/")))) return false; else return false; } }