【算法】逆波兰表达式

749 阅读2分钟

1. 前缀表达式(波兰表达式)

  • 例子:(3+4)*5-6 的前缀表达式是 - * + 3 4 5 6

  • 计算过程如下:从右至左扫描前缀表达式,遇到数字时,将数字压入栈,遇到运算符时,弹出栈顶的两个元素做运算,再将结果入栈。重复上述步骤,直到表达式最左端最后运算出结果。

2. 后缀表达式(逆波兰表达式)

  • 例子:(3+4)*5-6 的后缀表达式是 3 4 + 5 * 6 -
  • 计算过程如下:从左至右扫描后缀表达式,遇到数字时,将数字压入栈,遇到运算符时,弹出栈顶的两个元素做运算,再将结果入栈。重复上述步骤,直到表达式最右端最后运算出结果。(注意:遇到减号/除号时,是 次顶元素 减去/除去 栈顶元素)

2.1 计算算法

public static double calc(String postfixExpression, String separator) {
    if (postfixExpression == null || separator == null) {
        return 0;
    }
    Stack<Double> stack = new Stack<>();
    for (String item : postfixExpression.split(separator)) {
        // 匹配是数字
        if (item.matches("\\d+")) {
            stack.push(Double.valueOf(item));
        } else {
            Double num1 = stack.pop();
            Double num2 = stack.pop();
            double result;
            switch (item) {
                case "+": {
                    result = num2 + num1;
                    break;
                }
                case "-": {
                    result = num2 - num1;
                    break;
                }
                case "*": {
                    result = num2 * num1;
                    break;
                }
                case "/": {
                    result = num2 / num1;
                    break;
                }
                default: {
                    result = 0d;
                    break;
                }
            }
            stack.push(result);
        }
    }
    return stack.pop();
}

3. 中缀表达式转逆波兰表达式

3.1 思路步骤

1、初始化两个栈:运算符栈s1和存储中间结果的栈s2

2、从左至右扫描中缀表达式

3、如果遇到操作数时,将其压入s2

4、如果遇到运算符

4.1)如果s1为空,或者栈顶运算符为左括号"(",则直接将此运算符压入s1

4.2)否则,若该运算符的优先级比栈顶运算符的高,也将此运算符压入s1

4.3)否则,将s1栈顶的运算符弹出并压入s2,再回到步骤4.1继续比较

5、如果遇到括号

5.1)遇到的是左括号"(",则直接压入s1

5.2)遇到的是右括号")",则依次弹出s1栈顶的运算符,并压入s2,直到遇到左括号为止,将这对括号消除

6、重复步骤2-5,直到扫描完中缀表达式

7、将s1中剩余的运算符依次弹出并压入s2

8、将s2的元素依次弹出,其结果的逆序就是后缀表达式(整个过程s2可以用一个队列代替)

3.2 代码实现

public class PostfixExpression {
    private static final Map<String, Integer> OPERATOR_MAP = new HashMap<String, Integer>() {
        {
            put("+", 0);
            put("-", 1);
            put("*", 2);
            put("/", 3);
            put("(", 4);
        }
    };
    private static final int[][] OPERATOR_PRIORITY = new int[][]{
            {0, 0, -1, -1, 1},
            {0, 0, -1, -1, 1},
            {1, 1, 0, 0, 1},
            {1, 1, 0, 0, 1},
            {-1, -1, -1, -1, 0}
    };

    public static void main(String[] args) {
        String postfixExpression = getPostfixExpression("1+((2+3)*4)-5");
        System.out.println(postfixExpression);
    }

    public static String getPostfixExpression(String infixExpression) {
        return getPostfixExpression(infixExpression, " ");
    }

    /**
     * 中缀表达式转换为逆波兰表达式
     */
    public static String getPostfixExpression(String infixExpression, String separator) {
        if (infixExpression == null || "".equals(infixExpression)) {
            return "";
        }
        List<String> element = getElement(infixExpression);
        Stack<String> operatorStack = new Stack<>();
        List<String> result = new ArrayList<>();

        for (String item : element) {
            if (!isOperator(item)) {
                result.add(item);
            } else if ("(".equals(item)) {
                operatorStack.push(item);
            } else if (")".equals(item)) {
                while (!"(".equals(operatorStack.peek())) {
                    result.add(operatorStack.pop());
                }
                operatorStack.pop();
            } else {
                while (operatorStack.size() != 0 && judgePriority(operatorStack.peek(), item) >= 0) {
                    result.add(operatorStack.pop());
                }
                operatorStack.push(item);
            }
        }
        while (operatorStack.size() > 0) {
            result.add(operatorStack.pop());
        }
        if (separator == null) {
            separator = " ";
        }
        return String.join(separator, result);
    }

    private static boolean isOperator(char c) {
        return c == '+' || c == '-' || c == '*' || c == '/'
                || c == '(' || c == ')';
    }

    private static boolean isOperator(String str) {
        return "+".equals(str) || "-".equals(str) || "*".equals(str) || "/".equals(str)
                || "(".equals(str) || ")".equals(str);
    }

    private static List<String> getElement(String infixExpression) {
        List<String> element = new ArrayList<>();
        List<Character> operand = new ArrayList<>();
        for (char c : infixExpression.toCharArray()) {
            if (isOperator(c)) {
                if (operand.size() > 0) {
                    element.add(getOperand(operand));
                    operand.clear();
                }
                element.add(String.valueOf(c));
            } else {
                operand.add(c);
            }
        }
        if (operand.size() > 0) {
            element.add(getOperand(operand));
            operand.clear();
        }
        return element;
    }

    private static String getOperand(List<Character> operand) {
        StringBuilder sb = new StringBuilder();
        for (char c : operand) {
            sb.append(c);
        }
        return sb.toString();
    }

    private static int judgePriority(String operator1, String operator2) {
        int num1 = OPERATOR_MAP.getOrDefault(operator1, 0);
        int num2 = OPERATOR_MAP.getOrDefault(operator2, 0);
        return OPERATOR_PRIORITY[num1][num2];
    }
}

4. 相关链接