天天看点

数据结构与算法 — 前缀、中缀、后缀表达式

中缀表达式:

表达式中操作符位于操作符中间

,如:(3+4)*5-6,上述通过栈实现的即中缀表达式计算器。
前缀表达式(

波兰表达式

):

表达式中运算符在操作数前面

,计算机在进行计算时

从右往左

依次扫描,遇到操作数压入操作数栈,遇到操作符弹出操作数栈栈顶的两个元素进行元素,并将其结果压入操作数栈继续扫描。最终得到计算结果。
如:(3+4)*5-6 =>

"- 6 * 5 + 4 3"

后缀表达式(

逆波兰表达式,更适合计算机的运行

):

表达式中运算符在操作数后面

,计算机在进行计算时

从左往右

依次扫描,遇到操作数压入操作数栈,遇到操作符弹出操作数栈栈顶的两个元素进行元素,并将其结果压入操作数栈继续扫描。最终得到计算结果。
如:(3+4)*5-6 =>

"3 4 + 5 * 6 -"

中缀表达式基于栈的计算器实现:
package 栈;

import java.util.Stack;

/**
 * @author lyq on 2019-12-24 9:53 上午
 * @desc 栈实现表达式(只含+、-、*、"\")计算器
 * 实现思路:
 *  创建两个栈分别用于存放 操作数 和 操作符;
 *  遍历表达式:
 *      - 如果遍历元素为数直接入操作数栈;
 *      - 如果遍历元素为操作符:
 *          - 如果当前操作符优先级小于等于操作数栈当前栈顶元素的优先级,则从操作数栈中弹出两个操作数,并从符号栈弹出栈顶符号,根据弹出的操作符执行运算;
 *              将结果入操作数栈;将当前操作符入操作数栈;
 *          - 如果当前操作符优先级大于操作数栈当前栈顶元素的优先级,则入操作数栈。
 */
public class StackCalculation {

    private String expression = null;

    public StackCalculation(String expression) {
        this.expression = expression;
    }

    public void calculate(){
        // 存放操作数的栈
        Stack<Integer> numStack = new Stack();
        // 存放操作符的栈
        Stack<Character> operStack = new Stack<>();
        char[] chars = expression.toCharArray();
        // 用于处理
        String tempMultiNum = "";
        for (int i = 0;i < chars.length;i++) {
            char c = chars[i];
            if (!checkOperation(c)) {
                tempMultiNum += c;
                if (i == (chars.length-1)) {
                    numStack.push(Integer.parseInt(tempMultiNum));
                }
                continue;
            } else {
                if (tempMultiNum.length() > 0) {
                    numStack.push(Integer.parseInt(tempMultiNum));
                    tempMultiNum = "";
                }
                if (operStack.isEmpty()) {
                    operStack.push(c);
                } else {
                    int cur = getPriority(c);
                    int top = getPriority(operStack.peek());
                    if (cur > top) {
                        operStack.push(c);
                    } else {
                        Integer numLater = numStack.pop();
                        Integer numBefore = numStack.pop();
                        Character topOper = operStack.pop();
                        int tempResult = cal(numBefore, numLater, topOper);
                        numStack.push(tempResult);
                        operStack.push(c);
                    }
                }
            }
        }
        while (!operStack.isEmpty()) {
            Integer numLater = numStack.pop();
            Integer numBefore = numStack.pop();
            Character topOper = operStack.pop();
            int tempResult = cal(numBefore, numLater, topOper);
            numStack.push(tempResult);
        }
        System.out.println(numStack.pop());
    }

    /**
     * 获取操作符的优先级
     * @param c
     * @return
     */
    private int getPriority(char c){
        if (c == '*' || c == '/') {
            return 1;
        } else if (c == '+' || c == '-') {
            return 0;
        } else {
            return -1;
        }
    }

    /**
     * 检查遍历元素是否为操作符
     * @param c
     * @return
     */
    private boolean checkOperation(char c) {
        if (c == '+' || c == '-' || c == '*' || c == '/') {
            return true;
        }
        return false;
    }

    /**
     * 计算结果
     * @param numBefore
     * @param numLater
     * @param oper
     * @return
     */
    private int cal(int numBefore, int numLater, char oper){
        int tempResult = 0;
        switch (oper) {
            case '+':
                tempResult = numLater + numBefore;
                break;
            case '-':
                tempResult = numBefore - numLater;
                break;
            case '*':
                tempResult = numBefore * numLater;
                break;
            case '/':
                tempResult = numBefore/numLater;
                break;
            default:
                break;
        }
        return tempResult;
    }

    public static void main(String[] args) {
        StackCalculation stackCalculation = new StackCalculation("70*2+2-5*3-1");
        stackCalculation.calculate();
    }
}
           
中缀表达式转后缀表达式

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

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

3、扫描到操作数时压入s2;

4、扫描到运算符时:

(1)如果s1为空 或 s1栈顶为"(" 或 该运算符优先级高于s1栈顶运算符,则将该运算符入s1;

(2)否则将s1栈顶运算符压入s2,继续执行 4.(1) 的操作;

5、遇到括号时:

(1)如果是"(“直接压入s1;

(2)如果是”)“则依次弹出s1栈顶运算符压入s2,直到遇到”(",此时将这一对括号丢弃。

6、重复2-5,直到表达式最右边;

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

8、依次弹出s2中的元素并输出,

结果的逆序即为该中缀表达式的后缀表达式

package 栈;

import java.util.ArrayList;
import java.util.List;
import java.util.Stack;

/**
 * @author lyq on 2019-12-24 2:05 下午
 * @desc 中缀表达式转后缀表达式
 */
public class MidToSufferExp {

    private String midExp;

    public MidToSufferExp(String midExp) {
        this.midExp = midExp;
    }

    /**
     * 将中缀表达式转换为list
     * @return
     */
    public static List<String> convertToList(String midExp){
        List<String> result = new ArrayList<>();
        int i = 0;
        char c;
        // 多位数
        String multiNum;
        do {
            c = midExp.charAt(i);
            // 如果c不是数字
            if (c < 48 || c > 57) {
                result.add(String.valueOf(c));
                i++;
            } else {
                multiNum = "";
                while (i < midExp.length() && (c = midExp.charAt(i)) >= 48 && (c = midExp.charAt(i)) <= 57) {
                    multiNum += midExp.charAt(i);
                    i++;
                }
                result.add(multiNum);
            }
        } while (i < midExp.length());
        return result;
    }

    public static Stack convertToSuffuxExp(List<String> list) {
        Stack<String> s1 = new Stack<>();
        Stack<String> s2 = new Stack<>();
        for (String s : list) {
            // 如果是数字直接入s2
            if (s.matches("\\d+")) {
                s2.push(s);
            // 如果是"(" 直接入s1
            } else if (s1.size() == 0 || s.equals("(")){
                s1.push(s);
            // 如果是")",则执行括号消除操作
            } else if (s.equals(")")) {
                while (!(s1.peek().equals("("))){
                    s2.add(s1.pop());
                }
                // 消除括号
                s1.pop();
            } else {
                // 获取当前操作符的优先级
                int cur = getPriority(s);
                while ((!s1.isEmpty()) && (getPriority(s1.peek()) >= getPriority(s))) {
                    s2.push(s1.pop());
                }
                s1.push(s);
            }
        }
        while (!s1.isEmpty()) {
            s2.push(s1.pop());
        }
        return s2;
    }

    private static int getPriority(String s){
        if (s.equals("*") || s.equals("/")) {
            return 1;
        } else if (s.equals("+") || s.equals("-")) {
            return 0;
        } else {
            return -1;
        }
    }

    public static void main(String[] args) {
        String midExp = "3+(70*2)-6/2+3";
        List<String> list = convertToList(midExp);
        Stack stack = convertToSuffuxExp(list);
        while (!stack.isEmpty()) {
            System.out.println(stack.pop());
        }
    }
}