逆波兰式

定义:
中缀表达式:我们平时写的数学表达式一般为中缀表达式,如“5+2(3(3-12+1))”,直接拿中缀表达式直接让计算机计算表达式的结果并不能做到。
后缀表达式:把中缀表达表达式“5+2
(3(3-12+1))”转化“523312-1++”这样的形式,就是后缀表达式。这种记法叫做后缀(postfix)或逆波兰(reverse Polish)记法。计算这个问题最容易的方法就是使用一个栈。
转换方法:
按次序读取中缀表达式的字符。
读到一个操作数的时候,立即放入到输出中。
读到操作符“+”,“-”,“
”,“/”,则从栈中弹出栈元素并输出,直到遇到优先级更低或者“(”的为止操作符为止(该元素不出栈)。
读到操作符“(”,则直接把“(”压入栈中。
读到操作符“)”,则从栈中弹出栈元素并输出,直到遇到第一个“(”为止。其中“(”不再添加到输出中,而是直接舍弃。
当输入为空时,把栈里的操作符全部依次弹出并输出。
举例:
输入:

操作
说明

输出
读取5 把操作数直接输出 5
读取+ 栈为空,把操作符压入栈 + 5
读取2 把操作数直接输出 + 52
读取* 栈顶元素为+,优先级低于,把操作符压入栈 + 52
读取( 把 ( 直接压入栈 +( 52
读取3 把操作数直接输出 +
( 523
读取* 栈顶元素为(,把操作符压入栈 +( 523
读取( 把 ( 直接压入栈 +(( 523
读取3 把操作数直接输出 +(( 5233
读取- 栈顶元素为(,把操作符压入栈 +((- 5233
读取1 把操作数直接输出 +((- 52331
读取* 栈顶元素为-,优先级低于,把操作符压入栈 +((- 52331
读取2 把操作数直接输出 +((-* 523312
读取+ 栈顶元素为,优先级高于+,以此弹出,-到输出,到 ( 停止,把操作符压入栈中 +((+ 523312-
读取1 把操作数直接输出 +
((+ 523312-1
读取) 从栈中弹出+到输出,遇到第一个 ( 停止,把 ( 弹出栈 +( 523312-1+
读取) 从栈中弹出
到输出,遇到第一个 ( 停止,把 ( 弹出栈 +* 523312-1+
结束读取 把栈中的元素全部弹出到输出 523312-1+*+
输出后缀表达式:

后缀表达式的计算:
按次序读取后缀表达式的每一个字符。
读取到操作数时,把操作数压入栈中。
读取到操作符时,对栈顶的2个操作数做相应运算,要注意操作数的前后顺序。结果压入栈中。
读取完所有的字符后,弹出栈。得到的值就是所求结果。

算法如下:

import java.util.Stack;


public class Main {

    static Stack<Character> op = new Stack<>();

    public static Float getv(char op, Float f1, Float f2){
        if(op == '+') return f2 + f1;
        else if(op == '-') return f2 - f1;
        else if(op  == '*') return f2 * f1;
        else if(op == '/') return f2 / f1;
        else return Float.valueOf(-0);
    }

    /**
     * calculate the value of the reverse Polish expression
     * @param rp - reverse Polish expression
     * @return - result of the expression
     */
    public static float calrp(String rp){
        Stack<Float> v = new Stack<>();
        char[] arr = rp.toCharArray();
        int len = arr.length;
        for(int i = 0; i < len; i++){
            Character ch = arr[i];

            // if is operand, push to the stack
            if(ch >= '0' && ch <= '9') v.push(Float.valueOf(ch - '0'));

                // if is operator, calculate the result
                // with top 2 operands in the stack,
                // push the result into the stack
            else v.push(getv(ch, v.pop(), v.pop()));
        }
        return v.pop();
    }

    /**
     * from infix to postfix
     * @param s - String in the form of infix
     * @return String in the form of postfix
     */
    public static String getrp(String s){
        char[] arr = s.toCharArray();
        int len = arr.length;
        String out = "";

        for(int i = 0; i < len; i++){
            char ch = arr[i];
            if(ch == ' ') continue;

            // if is operand, add to 
            // the output stream directly
            if(ch >= '0' && ch <= '9') {
                out+=ch;
                continue;
            }

            //if is '(', push to the stack directly
            if(ch == '(') op.push(ch);

            //if is '+' or '-', pop the operator 
            // from the stack until '(' and add to 
            // the output stream
            //push the operator to the stack
            if(ch == '+' || ch == '-'){
                while(!op.empty() && (op.peek() != '('))
                    out+=op.pop();
                op.push(ch);
                continue;
            }

            //if is '*' or '/', pop the operator stack and 
            // add to the output stream 
            // until lower priority or '('
            //push the operator to the stack
            if(ch == '*' || ch == '/'){
                while(!op.empty() && (op.peek() == '*' || op.peek() == '/'))
                    out+=op.pop();
                op.push(ch);
                continue;
            }

            //if is ')' pop the operator stack and 
            // add to the output stream until '(', 
            // pop '('
            if(ch == ')'){
                while(!op.empty() && op.peek() != '(')
                    out += op.pop();
                op.pop();
                continue;
            }
        }
        while(!op.empty()) out += op.pop();
        return out;
    }

    public static void main(String[] args){
        //constraint: the operand should be 
        // equal or greater than 0 
        // but equal or less than 9
        String exp = "5+2*(3*(2-1))";
        System.out.println(calrp(getrp(exp)));
    }

}

逆波兰式的求值解法:

class Solution {
    public int evalRPN(String[] tokens) {
      // Stack<Integer> stack = new Stack<>();
      // for(String token : tokens){
      //   if("+".equals(token)){
      //     stack.push(stack.pop() + stack.pop());
      //   }else if("-".equals(token)){
      //     stack.push(-stack.pop() + stack.pop());
      //   }else if("*".equals(token)){
      //     stack.push(stack.pop() * stack.pop());
      //   }else if("/".equals(token)){
      //     int num = stack.pop();
      //     stack.push(stack.pop() / num);
      //   }else{
      //     stack.push(Integer.parseInt(token));
      //   }
      // }
      // return stack.pop();
          Stack stack = new Stack();
          for(int i=0;i<tokens.length;i++){
              String tokeni = tokens[i];
              if(tokeni.equals("+") || tokeni.equals("-") || tokeni.equals("*") || tokeni.equals("/")){
                  int v1 = (Integer) stack.pop();
                  int v2 = (Integer) stack.pop();
                  if(tokeni.equals("+")){
                      stack.push(v2+v1);
                  }
                  if(tokeni.equals("-")){
                      stack.push(v2-v1);
                  }
                  if(tokeni.equals("*")){
                      stack.push(v2*v1);
                  }
                  if(tokeni.equals("/")){
                      int res = v2/v1;
                      stack.push(res);
                  }
              }else{
                  stack.push(Integer.parseInt(tokeni));
              }
          }
          return (Integer) stack.peek();
    }
}

推荐阅读更多精彩内容