逆波蘭表達式


逆波蘭式(Reverse Polish notation,RPN)是波蘭邏輯學家J・盧卡西維茲(J・ Lukasiewicz)於1929年首先提出的一種表達式的表示方法 ,也叫后綴表達式。
一般的表達式又稱中綴表達式,這種表達式的二元運算符放在兩個運算量之間。而逆波蘭表達式又稱后綴表達式,這種表達式把運算符放在運算量后面。
例如: a+b 的逆波蘭式表示為 ab+
它的優勢在於只用兩種簡單操作,入棧和出棧就可以搞定任何普通表達式的運算。其運算方式如下:
如果當前字符為變量或者為數字,則壓棧,如果是運算符,則將棧頂兩個元素彈出作相應運算,結果再入棧,最后當表達式掃描完后,棧里的就是結果。

import java.util.ArrayList;
import java.util.Deque;
import java.util.LinkedList;
import java.util.List;

/**
 * <h3>逆波蘭表達式示例</h3><br>
 */
public class ReversePolishNotation {

    public static void main(String[] args) {
        String expression = "A+B+((C+D*E)+F*G)+H/I-J";
        List<String> infix = splitInfixExpression(expression);
        List<String> rpn = toReversePolishNotation(expression);
        String result = calculateReversePolishNotation(rpn);
        System.out.println(expression);
        System.out.println(infix);
        System.out.println(rpn);
        System.out.println(result);
    }

    /**
     * 拆分中序表達式
     * @param expression 中序表達式
     * @return 拆分后的元素列表
     */
    private static List<String> splitInfixExpression(String expression) {
        List<String> elements = new ArrayList<>();
        for (int i = 0, j = 0, k = expression.length() - 1; i <= k; i++) {
            char c = expression.charAt(i);
            // 運算符
            if (c == '+' || c == '-' || c == '*' || c == '/' || c == '(' || c == ')') {
                if (i != j) {
                    elements.add(expression.substring(j, i));
                }
                elements.add(String.valueOf(c));
                j = i + 1;
            } else if (i == k) {
                elements.add(expression.substring(j));
            }
        }
        return elements;
    }

    /**
     * 檢查算術表達術括號是否匹配, 語法是否正確
     * @param expression 算術表達術
     * @return 語法是否正確
     */
    public static boolean isMatch(String expression) {
        // 括號符號棧
        Deque<Character> stack = new LinkedList<>();

        // 遍歷字符串
        for (int i = 0; i < expression.length(); i++) {
            char c = expression.charAt(i);
            // 括號開始
            if (c == '(') {
                stack.push(c);
            } else if (c == ')') {
                // 括號結束 ,且棧為空則返回 false
                if (stack.isEmpty()) {
                    return false;
                }
                // 且棧不為空彈出棧頂
                else {
                    stack.pop();
                }
            }
        }
        // 棧為空(所有括號已經閉合)則表達式正確
        return stack.isEmpty();
    }

    /**
     * 解析表達式,獲取逆波蘭式
     * @param expression 表達式
     * @return 逆波蘭式隊列
     */
    public static List<String> toReversePolishNotation(String expression) {

        if (!isMatch(expression)) {
            throw new RuntimeException("Expression parentheses do not match!");
        }

        // 逆波蘭表達式棧
        List<String> result = new ArrayList<>();
        // 運算符棧(棧底到棧頂遞增。棧頂必須大於下面的)
        Deque<String> stack = new LinkedList<>();

        // 遍歷表達式元素
        for (String element : splitInfixExpression(expression)) {
            // 運算符
            if (isOperator(element)) {
                // 檢測棧頂與當前優先級關系,如果棧頂大於等於當前則出棧並輸出;直至棧頂小於當前,並將當前操作符入棧
                while (!stack.isEmpty() && getPriority(stack.peek()) > getPriority(element)) {
                    result.add(stack.pop());
                }
                stack.push(element);
            }
            // 左括號
            else if ("(".equals(element)) {
                stack.push(element);
            }
            // 右括號
            else if (")".equals(element)) {
                // 只要操作符不為左括號則一直輸出
                for (String top = stack.pop(); !"(".equals(top); top = stack.pop()) {
                    result.add(top);
                }
            }
            // 運算量
            else {
                result.add(element);
            }
        }
        // 依次彈出棧中剩下的操作符,並輸出
        while (!stack.isEmpty()) {
            String top = stack.pop();
            if (!"(".equals(top)) {
                result.add(top);
            }
        }
        return result;
    }

    /**
     * 計算逆波蘭式
     * @param rpn 逆波蘭式序列
     * @return 逆波蘭式結果
     */
    public static String calculateReversePolishNotation(List<String> rpn) {
        Deque<String> stack = new LinkedList<>();
        for (String element : rpn) {
            if (isOperator(element)) {
                String value2 = stack.pop();
                String value1 = stack.pop();
                stack.push("(" + value1 + element + value2 + ")");
            } else {
                // 操作量入棧
                stack.push(element);
            }
        }
        return stack.pop();
    }

    /**
     * 判斷是否為操作符 + - * /
     * @param value 字符
     * @return 是否操作符
     */
    private static boolean isOperator(String value) {
        return "+".equals(value) || "-".equals(value) || "*".equals(value) || "/".equals(value);
    }

    /**
     * 獲得運算符優先級
     * @param operator 運算符
     * @return 運算符優先級
     */
    private static int getPriority(String operator) {
        switch (operator) {
        case "*":
        case "/":
            return 2;
        case "+":
        case "-":
            return 1;
        case "(":
            return 0;
        default:
            throw new RuntimeException("Unsupported Operator [" + operator + "] !");
        }
    }
}


免責聲明!

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



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