中缀表达式如何转后缀表达式?

1,456 阅读3分钟

中缀表达式转后缀表达式

中缀表达式

  • 就是我们平常所使用的计算方式就叫中缀表达式,即运算符在中间,运算符的左右各有一个操作数
  • 例如:1 + 2 2 * 3
  • 但中缀表达式不容易被计算机解析

后缀表达式

  • 后缀表达式就是运算符在最右边,两个操作数都在运算符的左边
  • 例如:把 a + b 写成 a b + ,就是把中缀表达式转成了后缀表达式

技巧:

  1. 首先以乘除加减的顺序加上括号。
  2. 然后由里向外或者由外向里将运算符挪到对应的括号外面。
  3. 去掉括号,就得到了后缀表达式。

不可能的出栈顺序

如何把(2+4)* 3 - 1 这个中缀表达式转为后缀表达式?

1、第一步:加括号,根据运算的优先级加上对应的括号即可~ (((2+4)* 3 )- 1) 2、第二步:移运算符,将运算符移到右边第一个括号的外面 (((24)+ 3 )* 1)- 3、第三步:去括号, 24+ 3 * 1- 4、第四步:使用栈的思想计算出来

  • 2、4 是操作数就入栈
  • 遇到 运算符 了就出栈,第一个出栈的数字放运算符的右边,第二个出栈的放运算符的左边,然后将计算出的结果再入栈
  • 如此循环即可得出答案~

计算流程图

经典题目

题目1

栈的压入、弹出序列

题目分析:

  1. 先让第一个元素入栈
  2. 每次入栈之后就判断栈顶元素和 popA 数组 j 下标的元素是否相等,相等则栈顶元素弹出,数组 popA 的指针 j 也往后走一步。
  3. 走完循环看栈是否为空

代码

public boolean IsPopOrder(int [] pushA,int [] popA) {
    if (pushA == null || popA == null) return false;
    Stack<Integer> stack = new Stack<>();
    int j = 0;
    for (int i = 0; i < pushA.length; i++) {
        stack.push(pushA[i]);
        while (!stack.isEmpty() && stack.peek() == popA[j] && j < popA.length) {
            stack.pop();
            j++;
        }
    }
    return stack.isEmpty();
}

题目2

逆波兰表达式求值

代码

public int evalRPN(String[] tokens) {
    Stack<Integer> stack = new Stack<>();
    for (int i = 0; i < tokens.length; i++) {
        String ch = tokens[i];
        if (!check(ch)) {
            stack.push(Integer.parseInt(ch));
        } else {
            int num2 = stack.pop();
            int num1 = stack.pop();
            switch (ch) {
                case "+":
                    stack.push(num1 + num2);
                    break;
                case "-":
                    stack.push(num1 - num2);
                    break;
                case "*":
                    stack.push(num1 * num2);
                    break;
                case "/":
                    stack.push(num1 / num2);
                    break;
            }
        }
    }
    return stack.pop();
}

private boolean check(String s) {
    return s.equals("+") || s.equals("-") || s.equals("*") || s.equals("/");
}

题目3

括号匹配问题

题目分析:

总共有一下四种情况:

  1. 左右括号不匹配
  2. 左括号比右括号多
  3. 右括号比左括号多
  4. 匹配成功

代码

public boolean isValid(String s) {
    if (s == null) return true;
    Stack<Character> stack = new Stack<>();
    for (char ch : s.toCharArray()) {
        if (ch == '(' || ch == '[' || ch == '{') {
        	// 只要是左括号就进栈
            stack.push(ch);
        } else {
        	// 走到这就是右括号了,看是否匹配
            if (stack.isEmpty()) return false;
            char top = stack.peek();
            if ((ch == ')' && top == '(') || (ch == ']' && top == '[') || (ch == '}' && top == '{')) {
                stack.pop();// 匹配成功就弹出
            } else {
            	// 走到这说明,左括号比右括号多
                return false;
            }
        }
    }
    // 栈不为空则说明,右括号比左括号多
    return stack.isEmpty();
}

题目4

最小栈

题目分析:

  1. 准备一个普通栈和一个最小栈
  2. 普通栈每个元素都要入,不需要判断。最小栈就是要保证栈顶元素是普通栈中最小的那个元素
  3. 最小栈入栈的话,就需要每次让普通栈和最小栈比较,如果比最小栈的栈顶元素都要小,就将这个元素也入到最小栈中
  4. 删除普通栈中的元素的时候也需要和最小栈的栈顶元素比较,可能你要删除的就是最小值~

代码

public class MinStack {

    // 普通栈
    private Stack<Integer> stack;
    // 最小栈,存放最小元素
    private Stack<Integer> minStack;

    public MinStack() {
        stack = new Stack<>();
        minStack = new Stack<>();
    }

    //将元素val推入堆栈
    public void push(int val) {
        stack.push(val);
        if (minStack.empty()) {
            minStack.push(val);
        } else {
            int top = minStack.peek();
            if (val <= top) {
                minStack.push(val);
            }
        }
    }

    //删除堆栈顶部的元素
    public void pop() {
        if (stack.empty()) return;
        int tmp = stack.pop();
        int top = minStack.peek();
        if (tmp == top) {
            minStack.pop();
        }
    }

    //获取堆栈顶部的元素
    public int top() {
        if (stack.empty()) return -1;
        return stack.peek();
    }

    //获取堆栈中的最小元素
    public int getMin() {
        if (minStack.empty()) return -1;
        return minStack.peek();
    }

}