后缀表达式是什么?

后缀表达式也是逆波兰表达式,而波兰表达式就是前缀表达式。

一个表达式E的后缀形式可以如下定义:

(1)如果E是一个变量或常量,则E的后缀式是E本身。

(2)如果E是E1 op E2形式的表达式,这里op是任何二元操作符,则E的后缀式为E1'E2' op,这里E1'和E2'分别为E1和E2的后缀式。

(3)如果E是(E1)形式的表达式,则E1的后缀式就是E的后缀式。

如:我们平时写a+b,这是中缀表达式,写成后缀表达式就是:ab+

(a+b)*c-(a+b)/e的后缀表达式为:

(a+b)*c-(a+b)/e

→((a+b)*c)((a+b)/e)-

→((a+b)c*)((a+b)e/)-

→(ab+c*)(ab+e/)-

→ab+c*ab+e/-

直接用明确的表达式可能更好理解如:


4 * 5 - 8 + 60 + 8 / 2(中缀) => 4 5 * 8 - 60 + 8 2 / +(后缀)


因为中缀表达式是人们常用的表达式,对应人来说很方便,但是对应计算机来说处理起来比较复杂

所以我们需要将中缀表达式转换成后缀表达式。

带括号的中缀表达式转换成后缀表达式后是没有括号存在的。

解决思路


1)初始化一个栈和一个集合:运算符栈operStack和储存中间结果的集合resList; 2)从左至右扫描中缀表达式; 3)遇到操作数时,将其加入resList; 4)遇到运算符时,比较其与operStack栈顶运算符的优先级: 4.1.如果operStack为空,或栈顶运算符为左括号,则直接将此运算符入栈; 4.2.否则,若优先级比栈顶运算符的高,也将运算符压入operStack; 4.3.否则,将operStack栈顶的运算符弹出并压入到resList中,再次转到(4.1)与operStack中新的栈顶运算符相比较; 5)遇到括号时: 5.1如果是左括号“(”, 则直接压入栈中 5.2如果是右括号“)”,则依次弹出operStack栈顶的运算符,并压入resList,直到遇到左括号为止,此时将这一对括号丢弃!!! 6)重复步骤2至5,直到表达式的最右边 7)将operStack中剩余的运算符依次弹出并压入resList 8)依次弹出resList中的元素并输出,结果的逆即为中缀表达式对应的后缀表达式


完整代码实现

/**
 * 实现将中缀表达式转换位后缀表达式
 *      4 * 5 - 8 + 60 + 8 / 2(中缀)  => 4 5 * 8 - 60 + 8 2 / +(后缀)
 *      1 + ( ( 2 + 3 ) * 4 ) - 5(中缀) => 1 2 3 + 4 * + 5 -(后缀)
 */
public class InfixExpressionToSuffixExpression {

    public static void main(String[] args) {
        //定义一个中缀表达式
        String infixExp = "1 + ( ( 2 + 3.5 ) * 4 ) - 5";
        //将中缀表达式存储在ArrayList中
        List<String> list;
        list = getListString(infixExp);
        //定义要转换成的后缀表达式
        List<String> suffixExp = infixExpToSuffixExp(list);
        System.out.println(suffixExp);
    }


    public static List<String> infixExpToSuffixExp(List<String> infixExp){
        //创建一个用来存储运算符的stack
        Stack<String> operStack = new Stack<>();
        //创建一个用来临时存储计算结果的operList
        List<String> resList = new ArrayList<>();
        //遍历infixExp
        for (String item : infixExp) {
            //如果是一个数,加入resList
            // 匹配正数,负数,小数的正则表达式: ^(\-|\+)?\d+(\.\d+)?$
            if (item.matches("^(\\-|\\+)?\\d+(\\.\\d+)?$")){
                resList.add(item);
            } else if (item.equals("(")) {
                operStack.push(item);
            } else if (item.equals(")")) {
                //如果是又括号,则依次弹出operStack中的运算符,并压入resList,直到遇到左括号为止,此时将这对括号丢弃
                while (!operStack.peek().equals("(")){
                    resList.add(operStack.pop());
                }
                operStack.pop(); // 消除左括号!!!
            }else {
                //当item的优先级小于等于栈顶的优先级时
                while ( operStack.size() != 0 &&
                        priority( item.charAt(0) ) <= priority( operStack.peek().charAt(0) ) ) {
                    resList.add(operStack.pop());
                }
                //还要将item压入栈
                operStack.push(item);
            }
        }
        ///将operStack中剩余的运算符依次加入resList中
        while (operStack.size() != 0){
            resList.add(operStack.pop());
        }
        return resList;
    }

    //返回运算符的优先级,用数字表示
    public static int priority(int oper){
        if (oper == '*' || oper == '/')
            return 1;
        if (oper == '+' || oper == '-')
            return 0;
        return -1;
    }
    

    public static List<String> getListString(String infixExpression) {
        // 将suffixExpression按照空格分割
        String[] split = infixExpression.split(" ");
        List<String> list = new ArrayList<>();
        for (String ele : split) {
            list.add(ele);
        }
        return list;
    }

}

 以上代码中的表达式需要用一个空格分开,否则可能会出现异常。