【数据结构与算法】中缀表达式转后缀表达式以及后缀表达式的计算

中缀表达式转后缀表达式

方式一

步骤

1️⃣ 如果遇到操作数,我们就直接将其输出。

2️⃣ 如果遇到操作符,则我们将其放入到栈中,遇到左括号时我们也将其放入栈中。

3️⃣ 如果遇到一个右括号,则将栈元素弹出,将弹出的操作符输出直到遇到左括号为止。注意,左括号只弹出并不输出。

4️⃣ 如果遇到任何其他的操作符,如(“+”, “*”,“(”)等,从栈中弹出元素直到遇到发现更低优先级的元素(或者栈为空)(或发现最近的左括号)为止。弹出完这些元素后,才将遇到的操作符压入到栈中。有一点需要注意,只有在遇到" ) "的情况下我们才弹出" ( ",其他情况我们都不会弹出" ( "。

5️⃣ 如果我们读到了输入的末尾,则将栈中所有元素依次弹出。

代码实现

package demo03;

import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Deque;

public class InfixToPostfixExpression {

    private char[] expression;

    private Deque<Character> stack;

    private ArrayList<Character> list;  // 保存答案

    public InfixToPostfixExpression(char[] ex) {
        this.expression = ex;
        stack = new ArrayDeque<>();
        list = new ArrayList<>();
    }

    public ArrayList process() {
        for (char c : expression) {
            if (isOperand(c)) {            //如果是操作数,入集合
                list.add(c);
            }
            else if (isBracket(c)) {       // 如果是括号
                if (isLeftBracket(c)) {     // 如果是左括号,入栈
                    stack.addLast(c);

                } else {                    // 如果是右括号
                    while (!stack.isEmpty() && stack.peekLast() != '(') {  // 一直弹出栈中元素知道遇到左括号(左括号也要但还没弹出)
                        list.add(stack.removeLast());
                    }
                    if (!stack.isEmpty()) stack.removeLast();  //移除栈中匹配的左括号

                }
            } else if (isOperator(c)) {   // 如果 c 是操作符
                if (stack.isEmpty()) {    // 如果栈空,则入栈
                    stack.addLast(c);
                }
                else {
                    // 计算优先值(0:相等,-1:c优先值低于栈顶,1:c优先值大于栈顶)
                    int priority = priority(c) - priority(stack.peekLast());
                    if (priority < 0) {     //遇到优先度低的,一直弹出来(直到遇到左括号)
                        while (!stack.isEmpty() && !isLeftBracket(stack.peekLast())) {
                            list.add(stack.removeLast());
                        }
                    }
                    stack.addLast(c);  // 最后 c 入栈
                }
            }
        }
        while (!stack.isEmpty()) {   // 栈中剩余元素都弹出并入集合
            list.add(stack.removeLast());
        }
        return list;
    }

    // 判断是否是操作数
    private boolean isOperand(char c) {
        return !(isOperator(c) || isBracket(c));

    }

    // 计算优先值
    private int priority(char c) {
        if (c == '+' || c == '-') return 0;
        else return 1;   //if (c == '*' || c == '/')
    }

    // 判断是否是左括号
    private boolean isLeftBracket(char c) {
        return c == '(';
    }

    // 判断是否是右括号
    private boolean isRightBracket(char c) {
        return c == ')';
    }

    // 判断是否是操作符
    public boolean isOperator(char c) {
        return c == '+' || c == '-' || c == '*' || c == '/';
    }

    // 判断是否是括号
    public boolean isBracket(char c) {
        return c == '(' || c == ')';
    }

}

测试

    public static void main(String[] args) {
        String ex = "a + b * c + (d * e + f)*g";
        ex = ex.trim().replace(" ", "");
        char[] e = ex.toCharArray();
        InfixToPostfixExpression expression = new InfixToPostfixExpression(e);
        ArrayList process = expression.process();
        System.out.println(process.toString());
        // 输出:[a, b, c, *, +, d, e, *, f, +, g, *, +]
    }

方式二

1️⃣ 先按照运算符的优先级对中缀表达式加括号,变成((a + (b * c)) + (((d * e) + f) * g ))

2️⃣ 将运算符移到括号的后面,变成((a(bc) * )+(((de) * f) + g) * ) +

3️⃣ 去掉括号,得到 abc *+ de * f + g *+

后缀表达式的计算

后缀表达式也叫逆波兰表达式。

逆波兰表达式严格遵循「从左到右」的运算。计算逆波兰表达式的值时,使用一个栈存储操作数,从左到右遍历逆波兰表达式,进行如下操作:

如果遇到操作数,则将操作数入栈;

如果遇到运算符,则将两个操作数出栈,其中先出栈的是右操作数,后出栈的是左操作数,使用运算符对两个操作数进行运算,将运算得到的新操作数入栈。

整个逆波兰表达式遍历完毕之后,栈内只有一个元素,该元素即为逆波兰表达式的值。

代码

class Solution {
    public int evalRPN(String[] tokens) {
        Deque<Integer> stack = new LinkedList<>();
        int n = tokens.length;
        for(int i = 0;i<n;i++){
            
            if(isNum(tokens[i])){
                stack.push(Integer.parseInt(tokens[i]));
            }else{
                int b = stack.pop();
                int a = stack.pop();
                switch(tokens[i]){
                    case "+":{
                        stack.push(a+b);
                        break;
                    }
                    case "-":{
                        stack.push(a-b);
                        break;
                    }
                    case "*":{
                        stack.push(a*b);
                        break;
                    }
                    case "/":{
                        stack.push(a/b);
                        break;
                    }
                }
            }
        }
        return stack.pop();
    }
    public boolean isNum(String s){
        return !(("+".equals(s))||("-".equals(s))||("*".equals(s))||("/".equals(s)));
    }
}
输入:tokens = ["10","6","9","3","+","-11","*","/","*","17","+","5","+"]
输出:22
解释:
该算式转化为常见的中缀算术表达式为:
  ((10 * (6 / ((9 + 3) * -11))) + 17) + 5
= ((10 * (6 / (12 * -11))) + 17) + 5
= ((10 * (6 / -132)) + 17) + 5
= ((10 * 0) + 17) + 5
= (0 + 17) + 5
= 17 + 5
= 22
posted @ 2021-10-04 23:33  gonghr  阅读(524)  评论(0编辑  收藏  举报