import java.util.HashMap;
import java.util.Stack;
/*
3. 后缀表达式
后缀表达式也称为逆波兰式(Reverse Polish Notation, RPN),更加广为人知一些,和前缀表达式刚好相反,是将操作符号放置于操作数之后,比如2 + 3 * (5 - 1)用逆波兰式来表示则是:2 3 5 1 - * +。
逆波兰式的计算也是从左往右依次读取,当读到操作符时,将之前的两个操作数做计算,然后替换这两个操作数和操作符,接着读取,重复此步骤。对于这个表达式,读到5 1 -,得到4,然后读取乘号,取出前面的3和上一步的计算结果4,并计算,到12,接着读取加号+,计算2 12 +得到14,计算结束。
上面这个步骤可以很容易的用栈来实现:
从左往右依次读取表达式,如果是数字则将该数字压栈,如果是符号,则将之前的两个数字出栈,做计算后,将计算结果压栈,直到表达式读取结束。栈中剩下的一个数就是计算结果。
逆波兰式看起来像波兰式反过来,比如5 + 1的波兰式是+ 5 1,逆波兰式为5 1 +或者1 5 +。也很明显,逆波兰式并不是简单的将波兰式反过来,因为,减法和除法中减数和被减数、除数与被除数是不能交换的,即- 10 5和- 5 10就完全不一样。
4. 中缀表达式到后缀表达式的转换
因为通过后缀表达式来进行计算只需要一个栈即可,从硬件和软件上实现都是极为便利的,因此逆波兰式在计算机领域的应用更加广泛,因此将中缀表达式转换为逆波兰式非常重要。
依然仅仅使用栈就可以将中缀表达式转换成逆波兰式,转换过程如下:
从左往右遍历中缀表达式中的每个数字和符号,弱是数字就输出,成为逆波兰式的一部分; 如果是右括号,或者是其他符号并且比当前栈顶符号的优先级低,则栈顶元素依次出栈并输出; 然后将当前符号进栈,重复以上操作直到结束。
还是以2 + 3 * (5 - 1)为例:
首先读入数字2,直接将其输出,输出为2,栈为空
接着读入加号+,由于栈为空,因此将其进栈,输出为2,栈为+
接着读入数字3,直接将其输出,输出为2 3,栈为+
接着读入乘号*,比栈顶元素优先级高,进栈,输出为2 3,栈为+ *
读入左括号(,直接进栈,输出2 3,栈为+ * (
读入数字5,直接将其输出,输出为2 3 5,栈为+ * (
读入减号-,栈顶元素为左括号,进栈,输出为2 3 5,栈为+ * ( -
读入数字1,直接将其输出,输出为2 3 5 1,栈为+ * ( -
读入右括号,依次输出栈顶元素,直到左括号,括号不输出,输出2 3 5 1 -,栈为+ *
已经无元素可读,依次输出栈顶元素,直到栈为空,输出2 3 5 1 - * +,栈为空
这样可以仅仅使用栈,首先将中缀表达式转换为逆波兰式,然后用本文第3节中的方法对后缀表达式进行求值,整个过程使用栈来完成即可。
5. 表达式树与逆波兰式
还可以通过另外一种方法来将一个表达式转换成波兰式和逆波兰式,这种方法依赖与树,首先需要根据表达式构建成树,仍然以2 + 3 * (5 - 1)为例,下图是其表达式树。
6. 后缀表达式计算
将表达式,依次取出来,存入Stack,遇到运算符, 依次取2个stack top element 进行运算,并结果压stack,直到中只有最后一个元素
*/
public class StackExp {
private final Stack
private final Stack
private final HashMap
public StackExp(){
mapping.put("+", 1);
mapping.put("-", 1);
mapping.put("*", 2);
mapping.put("%", 2);
mapping.put("/", 2);
mapping.put("^", 3);
mapping.put("(", 0);
mapping.put(")", 0);
mapping.put("|", -1);
}
public void transform(String expStr){
char[] chs=expStr.toCharArray();
for(int i=0;i
if(!mapping.containsKey(s)){
exps.add(s);
}else{
if("(".equals(s)){
oper.add(s);
}else if(")".equals(s)){
while(oper.size()>0 && !oper.peek().equals("(")){
exps.add(oper.pop());
}
oper.pop();
}else{
if(oper.isEmpty()){
oper.add(s);
}else{
int curOp=mapping.get(s);
int topOp=mapping.get(oper.peek());
if(curOp>topOp){
oper.add(s);
}else{
do{
exps.add(oper.pop());
}while(oper.size()>0 && (curOp<=mapping.get(oper.peek())));
oper.add(s);
}
}
}
}
}
while(oper.size()>0){
exps.add(oper.pop());
}
while(exps.size()>0){
oper.add(exps.pop());
}
printExp();
calculate();
System.out.println(exps.toString());
}
private void calculate(){
while(oper.size()>0){
String op=oper.pop();
if(mapping.containsKey(op)){
double d=calculate(op,Double.parseDouble(exps.pop()),Double.parseDouble(exps.pop()));
System.out.println(d);
exps.push(String.valueOf(d));
}else{
exps.push(op);
}
}
}
private void printExp(){
System.out.println(exps.toString());
}
private double calculate(String op,double d1, double d2){
if(op.equals("+")){
return d1+d2;
}
if(op.equals("-")){
return d1-d2;
}
if(op.equals("*")){
return d1*d2;
}
if(op.equals("/")){
return d1/d2;
}
if(op.equals("%")){
return d1%d2;
}
if(op.equals("^")){
return Math.pow(d1, d2);
}
return 0;
}
public static void main(String[] args) {
StackExp exp=new StackExp();
exp.transform("(1+2)*3-5+8+(1+2)*3-5+8");
}
}