Java版 逆波蘭表達式(后綴表達式)


逆波蘭表達式

又稱后綴表達式,將運算符寫在操作數之后,便於計算機計算

  • 將中綴表達式轉換成后綴表達式的8個步驟:
  1. 初始化兩個棧,運算符棧s1和存儲中間結果的棧s2

  2. 從左至右掃描中綴表達式

  3. 遇到操作數時,將其壓入s2

  4. 遇到運算符時,將其與s1棧頂運算符的優先級進行比較:

    1. 如果s1為空,或棧頂運算符為左括號"(",則直接將此運算符入棧
    2. 否則,若優先級比棧頂運算符的高,也將運算符壓入s1
    3. 否則,將s1棧頂的運算符彈出並壓入到s2中,再次轉到(4.1)與s1中的棧頂運算符相比較
  5. 遇到括號時:

    1. 如果是左括號"(",則直接壓入s1
    2. 如果是右括號")",則依次彈出s1棧頂的運算符,並壓入s2,直到遇到左括號為止,此時將這一對括號丟棄
  6. 重復步驟2至5,知道表達式最右邊

  7. 將s1中剩余的運算符以此彈出並壓入s2

  8. 依次彈出s2中的元素並輸入,結果的逆序即為中綴表達式對應的后綴表達式。

  • 1+(2+3)*4 -5 的轉換步驟

代碼實現

/**
 * 轉換成后綴表達式List
 *
 * @param ls 中綴表達式List
 * @return
 */
public static List<String> parseSuffixExpression(List<String> ls) {
    Stack<String> s1 = new Stack<>();//運算符棧
    Queue<String> s2 = new ArrayDeque<>();//臨時隊列

    for (String item : ls) {
        if (item.matches("\\d+")) {
            //3.如果是數字,直接入隊s2
            s2.offer(item);
        } else if (isOper(item)) {
            //4.如果是運算符
            while (true) {
                if (s1.isEmpty() || "(".equals(s1.peek())) {
                    //4.1如果運算符棧s1是空的,或棧頂是左括號,則直接入棧
                    s1.push(item);
                    break;
                } else if (priority(item) > priority(s1.peek())) {
                    //4.2否則,若運算符優先級比棧頂的高,也入棧
                    s1.push(item);
                    break;
                } else {
                    //4.3 否則,直接把棧頂的元素入隊,繼續轉到4.1與新的棧頂元素比較
                    s2.offer(s1.pop());
                }
            }
        } else if ("(".equals(item)) {
            //5.1如果遇到左括號( ,直接壓入s1
            s1.push(item);
        } else if (")".equals(item)) {
            //5.2如果是右括號
            while (true) {
                String top = s1.pop();//彈出棧頂元素
                if ("(".equals(top)) {
                    //碰到左括號,丟棄這對括號
                    break;
                } else {
                    //否則入隊
                    s2.offer(top);
                }
            }
        } else {
            throw new RuntimeException("無法識別的字符" + item + ",表達式不正確");
        }
    }
    while (!s1.isEmpty()) {
        //7.將s1剩余的表達式依次彈出並入隊
        s2.offer(s1.pop());
    }

    List<String> res = new ArrayList<>();
    while (!s2.isEmpty()) {
        res.add(s2.poll());
    }
    return res;
}

后綴表達式的計算規則:從左到右遍歷表達式的每個數字和符號,遇到是數字就進棧,遇到是符號,就將處於棧頂兩個數字出棧,進行運算,運算結果進棧,一直到最終獲得結果。

/**
 * 計算后綴表達式List,返回結果
 *
 * @param ls
 * @return
 */
public static int calculate(List<String> ls) {
    Stack<String> stack = new Stack<>();
    for (String item : ls) {
        if (item.matches("\\d+")) {
            //如果是數字則入棧
            stack.push(item);
        } else {
            //如果不是數字,則彈出棧頂和次棧頂元素進行計算
            int num2 = Integer.parseInt(stack.pop());
            int num1 = Integer.parseInt(stack.pop());
            int res = 0;
            if ("+".equals(item)) {
                res = num1 + num2;
            } else if ("-".equals(item)) {
                res = num1 - num2;
            } else if ("*".equals(item)) {
                res = num1 * num2;
            } else if ("/".equals(item)) {
                res = num1 / num2;
            } else {
                throw new RuntimeException("運算符有誤");
            }
            //計算過的結果再次入棧
            stack.push("" + res);
        }
    }
    //棧中的結果就是表達是的結果,直接返回
    return Integer.parseInt(stack.pop());	
}

簡單轉換(括號法)

1.按照運算符的優先級對所有的運算單位加括號~

2.把運算符號移動到對應的括號后面

3.去除所有括號

例:

  1. 1+2
    • (1+2)
    • (1 2)+
    • 1 2 +
  2. 1+2×3
    • (1+(2 × 3))
    • (1+(2 3)×)
    • (1 (2 3 ×) ) +
    • 1 2 3 × +
  3. (2-1)×3+15÷(1+4)
    • (((2 - 1) × 3) + (15 ÷ (1+4)))
    • (((2 1) - × 3) + (15 ÷ (1 4)+))
    • (((2 1) - 3) × + (15 (1 4)+) ÷ )
    • (((2 1) - 3) × (15 (1 4)+) ÷ ) +
    • 2 1 - 3 × 15 1 4 + ÷ +
//完整java代碼
import java.util.*;

/**
 * 逆波蘭表達式(后綴表達式)
 * 支持整數、浮點 + - * / ( )運算符,可自動過濾非法字符
 */
public class PolandNotation {
    public static void main(String[] args) {
        String expression = "(2.1-1)* 3.1+  15/(2+4)";
        System.out.println("中綴表達式:" + expression);
        List<String> list = toInfixExpressionList(expression);
        System.out.println("中綴表達式List:" + list);
        List<String> suffixExpression = parseSuffixExpression(list);
        System.out.println("后綴表達式List:" + suffixExpression);
        float calculate = calculate(suffixExpression);
        System.out.println("計算結果:" + calculate);
    }

    /**
     * 轉換成后綴表達式List
     *
     * @param ls 中綴表達式List
     * @return
     */
    public static List<String> parseSuffixExpression(List<String> ls) {
        Stack<String> s1 = new Stack<>();//運算符棧
        Queue<String> s2 = new ArrayDeque<>();//臨時隊列

        for (String item : ls) {
            if (item.matches(REGEX_FLOAT)) {
                //3.如果是數字,直接入隊s2
                s2.offer(item);
            } else if (isOper(item)) {
                //4.如果是運算符
                while (true) {
                    if (s1.isEmpty() || "(".equals(s1.peek())) {
                        //4.1如果運算符棧s1是空的,或棧頂是左括號,則直接入棧
                        s1.push(item);
                        break;
                    } else if (priority(item) > priority(s1.peek())) {
                        //4.2否則,若運算符優先級比棧頂的高,也入棧
                        s1.push(item);
                        break;
                    } else {
                        //4.3 否則,直接把棧頂的元素入隊,繼續轉到4.1與新的棧頂元素比較
                        s2.offer(s1.pop());
                    }
                }
            } else if ("(".equals(item)) {
                //5.1如果遇到左括號( ,直接壓入s1
                s1.push(item);
            } else if (")".equals(item)) {
                //5.2如果是右括號
                while (true) {
                    String top = s1.pop();//彈出棧頂元素
                    if ("(".equals(top)) {
                        //碰到左括號,丟棄這對括號
                        break;
                    } else {
                        //否則入隊
                        s2.offer(top);
                    }
                }
            } else {
                throw new RuntimeException("無法識別的字符" + item + ",表達式不正確");
            }
        }
        while (!s1.isEmpty()) {
            //7.將s1剩余的表達式依次彈出並入隊
            s2.offer(s1.pop());
        }

        List<String> res = new ArrayList<>();
        while (!s2.isEmpty()) {
            res.add(s2.poll());
        }
        return res;
    }

    /**
     * 是否操作符
     *
     * @param val 元素
     * @return
     */
    public static boolean isOper(String val) {
        return "+".equals(val) || "-".equals(val) || "*".equals(val) || "/".equals(val);
    }

    /**
     * 將中綴表達式轉換成對應的List
     *
     * @param s 中綴表達式字符串
     * @return
     */
    public static List<String> toInfixExpressionList(String s) {
        List<String> ls = new ArrayList<>();
        int i = 0;//指針,用於遍歷中綴表達式字符串
        String str;//對多位數的拼接工作
        char c;//每遍歷到一個字符,放入c
        do {
            c = s.charAt(i);//獲取元素
            if (c == '+' || c == '-' || c == '*' || c == '/' || c == '(' || c == ')') {
                //如果元素是運算符直接添加到List
                ls.add(c + "");
                i++;
            } else if (Character.isDigit(c) || c == '.') {
                //如果元素是數字和小數點
                str = "";
                while (i < s.length() && (Character.isDigit(s.charAt(i)) || s.charAt(i) == '.')) {//直至下個不是小數點或數字的位置
                    str += "" + s.charAt(i++);
                }
                ls.add(str);
            } else {
                i++;
            }
        } while (i < s.length());

        return ls;
    }


    /**
     * 返回操作符優先級
     *
     * @param operString 操作符
     * @return
     */
    public static int priority(String operString) {
        if ("*".equals(operString) || "/".equals(operString)) {
            return 1;
        } else if ("+".equals(operString) || "-".equals(operString)) {
            return 0;
        } else {
            return -1;
        }
    }

    /**
     * 數字正則
     */
    private final static String REGEX_FLOAT = "\\d+||\\d*\\.\\d+||\\d*\\.?\\d+?e[+-]\\d*\\.?\\d+?||e[+-]\\d*\\.?\\d+?";

    /**
     * 計算后綴表達式List,返回結果
     *
     * @param ls
     * @return
     */
    public static float calculate(List<String> ls) {
        Stack<String> stack = new Stack<>();
        for (String item : ls) {
            if (item.matches(REGEX_FLOAT)) {
                stack.push(item);//如果是數字則入棧
            } else {
                //如果不是數字,則彈出棧頂和次棧頂元素進行計算
                Float num2 = Float.parseFloat(stack.pop());
                Float num1 = Float.parseFloat(stack.pop());
                Float res = 0f;
                if ("+".equals(item)) {
                    res = num1 + num2;
                } else if ("-".equals(item)) {
                    res = num1 - num2;
                } else if ("*".equals(item)) {
                    res = num1 * num2;
                } else if ("/".equals(item)) {
                    res = num1 / num2;
                } else {
                    throw new RuntimeException("運算符有誤");
                }
                //計算過的結果再次入棧
                stack.push("" + res);
            }
        }
        //棧中的結果就是表達是的結果,直接返回
        return Float.parseFloat(stack.pop());
    }

}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM