Stack 表达式计算

package com.citi.ww03140.ds.exp;

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<String> exps=new Stack<String>();

private final Stack<String> oper=new Stack<String>();

private final HashMap<String,Integer> mapping=new HashMap<String,Integer>();

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<chs.length;i++){
String s=String.valueOf(chs[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");
}

}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值