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");
    }

}

你可能感兴趣的:(数据结构,stack,表达式)