前序表达式 , 中序表达式 , 后序表达式

  • 中序表达式
    中序表达式即我们日常使用的表达式,从左往右阅读,结构清晰,但是需要括号改变优先级,对计算机不友好
    eg:(1+4)*3+10/5,2*3/(2-1)+3*(4-1)
  • 前序表达式(波兰表示法Polish notation,或波兰记法)
    前序表达式的特点是操作符置于操作数前面,如果操作符的元数(+是二元操作符,故元数是2),则语法上不需要括号仍然能被无歧义的解释,不需要括号改变优先级。
    eg:
中序表达式: (1+4)*3+10/5
前序表达式: + * + 1 4 3 / 10 5

前序表达式的计算:
eg:
	+ * + 1 4 3 / 10 5
step1:	10 / 5 => 2 
new expression: + * + 1 4 3 2
step2:	1 + 4 => 5 
new expression: + * 5 3 2
step3:	5 * 3 => 15
new expression: + 15 2
step4:	15 + 2 => 17

前序表达式的求值:
首先要从右至左扫描表达式,从右边第一个字符开始判断,如果当前字符是数字则继续扫描,如果当前字符是运算符,将运算符右边最近的两个数字做运算,结果作为新的字符记录下来。
一直扫描到表达式的最左端时,最后运算的值也就是表达式的值。
  • 后序表达式(逆波兰表示法(Reverse Polish notation,RPN,或逆波兰记法)
    后序表达式所有的操作符置于操作数后面,因此也被称为后缀表示法。逆波兰表示法不需要括号标识操作符的优先级。
    eg:
中序表达式: (1+4)*3+10/5
后序表达式: 1 4 + 3 * 10 5 / +

后序表达式的计算:
eg:
	1 4 + 3 * 10 5 / +
step1:	1 + 4 => 5 
new expression: 5 3 * 10 5 / +
step2:	5 * 3 => 15
new expression: 15 10 5 / +
step3:	10 / 5 => 2
new expression: 15 2 +
step4:	15 + 2 => 17

后序表达式的求值:
后序表达式的求值和前序表达式十分相似,后序表达式是从左至右扫描表达式,从左边第一个字符开始判断,如果的那个字符是数字继续扫描,
如果是运算符,将运算符左边最近的两个数字做运算,结果作为新的字符记录下来。一直扫描到表达式的最右端时,最后运算的值也就是表达式的值。

中序表达式转后序表达式(暂时只实现四则运算级别的转化)

  • 创建一个队列和一个操作符栈
  • 遇到操作数则送入队列
  • 遇到操作符则送入栈
  • 遇到加减乘除运算符:弹出所有优先级大于或等于该运算符的栈顶元素,然后该运算符入栈
  • 遇到”(“括号直接入栈
  • 遇到”)"括号则将栈内直到“(”括号的所有操作符送入队列
  • 执行完成后,先输出队列内容,在输出栈内容,最终结果即是后序表达式
/**
 * 先序表达式 -> 后序表达式
 */
public String infixToPostfix(String[] elements) {
    String res = "";

    Stack<String> stack = new Stack<>();
    Queue<String> queue = new Queue<>();
    for (int i = 0; i < elements.length; i++) {
        String s = elements[i];

        if (s.equals("(")) {
            stack.push(s);
            continue;
        }
        if (s.equals(")")) {
            String pop = stack.pop();
            while (!pop.equals("(")) {
                queue.enqueue(pop);
                pop = stack.pop();
            }
            continue;
        }

        //碰到"+"或 "-"运算符
        if (s.equals("+") || s.equals("-")){
            if (stack.isEmpty()){
                stack.push(s);
                continue;
            }
            while (!stack.isEmpty() && !stack.peek().equals("(")){
                queue.enqueue(stack.pop());
            }
            stack.push(s);
            continue;
        }

        //碰到"*"或 "/"运算符
        if (s.equals("*") || s.equals("/")){
            if (stack.isEmpty()){
                stack.push(s);
                continue;
            }
            boolean peek = stack.peek().equals("*") || stack.peek().equals("/");
            while (!stack.isEmpty() && peek) {
                queue.enqueue(stack.pop());
            }
            stack.push(s);
            continue;
        }
        queue.enqueue(s);
    }

    //拼接后序表达式
    do{
        res += queue.dequeue() + " ";
    } while (!queue.isEmpty());
    do {
        res += stack.pop() + " ";
    } while (!stack.isEmpty());
    return res;
}

后序表达式的计算(暂时只实现了四则运算)

  • 从左至右扫描表达式
  • 如果字符是数字继续扫描,如果是操作符,取左边最近的两个操作数,运算后将结果压入栈中
  • 扫描到表达式的最右端时,最后运算的值也就是表达式的值
/**
 * 1.3.11  计算后序表达式的值
 */
public class EvaluatePostfix {

    public int evaluate(String[] postfix){
        Stack<String> stack = new Stack<>();
        for (int i = postfix.length - 1; i >= 0; i--) {
            stack.push(postfix[i]);
        }

        Stack<String> tmp = new Stack<>();
        String res = "";
        while (!stack.isEmpty()) {
            String pop = stack.pop();
            if (pop.equals("*") || pop.equals("/") || pop.equals("+") || pop.equals("-")){
                int rightValue = Integer.valueOf(tmp.pop());
                int leftValue = Integer.valueOf(tmp.pop());
                int sum = evaluate(leftValue, rightValue, pop);
                stack.push(sum + "");
                while (!tmp.isEmpty()){
                    stack.push(tmp.pop());
                }
                continue;
            }
            tmp.push(pop);
            res = pop;
        }
        return Integer.parseInt(res);
    }

    public int evaluate(int a, int b, String operator){
        switch (operator){
            case "*" : return a * b;
            case "/" : return a / b;
            case "+" : return a + b;
            case "-" : return a - b;
            default: throw new IllegalArgumentException("operator must be \"* / + -\"");
        }
    }
}