java數據結構與算法總結(四)--Java實現表達式計算(中綴表達式轉化爲後綴表達式/逆波蘭式)

在做一道算法題時遇到該問題,寫一個計算器其中有加減乘除和括號,用最快的算法算出來。後來根據答案想了下用下面的算法是複合答案的意思。

定義:

  • 中綴表達式:

我們平時寫的數學表達式一般爲中綴表達式,如“5+2*(3*(3-1*2+1))”,直接拿中綴表達式直接讓計算機計算表達式的結果並不能做到。

  • 後綴表達式:

把中綴表達表達式“5+2*(3*(3-1*2+1))”轉化“523312*-1+**+”這樣的形式,就是後綴表達式。這種記法叫做後綴(postfix)或逆波蘭(reverse Polish)記法。計算這個問題最容易的方法就是使用一個棧。
轉換方法:

  1. 按次序讀取中綴表達式的字符。
  2. 讀到一個操作數的時候,立即放入到輸出中。
  3. 讀到操作符“+”,“-”,“*”,“/”,則從棧中彈出棧元素並輸出,直到遇到優先級更低或者“(”的爲止操作符爲止(該元素不出棧)。
  4. 讀到操作符“(”,則直接把“(”壓入棧中。
  5. 讀到操作符“)”,則從棧中彈出棧元素並輸出,直到遇到第一個“(”爲止。其中“(”不再添加到輸出中,而是直接捨棄。
  6. 當輸入爲空時,把棧裏的操作符全部依次彈出並輸出。

舉例:

操作 說明 輸出
讀取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+**+

後綴表達式的計算:

  1. 按次序讀取後綴表達式的每一個字符。
  2. 讀取到操作數時,把操作數壓入棧中。
  3. 讀取到操作符時,對棧頂的2個操作數做相應運算,要注意操作數的前後順序。結果壓入棧中。
  4. 讀取完所有的字符後,彈出棧。得到的值就是所求結果。

代碼:

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

輸出:

11.0

————————————————
版權聲明:本文爲CSDN博主「Ring_k」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/ring_k/article/details/79598961

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章