Bootstrap

中缀表达式转后缀表达式_简单实现

本篇博客源于自己在做王道考研数据结构复习书的习题,只介绍解法,不说原理哦~(原理我也不知道)

先看一道简单的的题目:将中缀表达式 a / b + ( c ∗ d − e ∗ f ) / g a/b+(c*d-e*f)/g a/b+(cdef)/g转换成后缀表达式,当然用手来推,还是相对简单的,那怎么设计程序来自动实现呢?

思想如下:

  • 从左到右开始扫描中缀表达式:
  • 遇到数字时,加入后缀表达式:
  • 遇到运算符时:
    • 若为'(',则入栈;
    • 若为')',则依次把栈中的运算符加入后缀表达式,直到出现'(',从栈中删除'('
    • 若为除括号外的其他运算符,当其优先级高于除'('外的栈顶运算符时,直接入栈。否则从栈顶开始,依次弹出比当前处理的运算符优先级高和优先级相等的运算符,直到一个比它优先级低的或遇到了一个左括号为止。

如果只看上面说的,我相信你可能不太懂,所以下面我们拿一道例题来一步一步看看。

待处理序列后缀表达式当前扫描元素动作
a / b + ( c ∗ d − e ∗ f ) / g a/b+(c*d-e*f)/g a/b+(cdef)/gaa加入到后缀表达式
/ b + ( c ∗ d − e ∗ f ) / g /b+(c*d-e*f)/g /b+(cdef)/ga//入栈
b + ( c ∗ d − e ∗ f ) / g b+(c*d-e*f)/g b+(cdef)/g/abb加入到后缀表达式
+ ( c ∗ d − e ∗ f ) / g +(c*d-e*f)/g +(cdef)/g/ab++优先级低于栈顶的/,弹出/
+ ( c ∗ d − e ∗ f ) / g +(c*d-e*f)/g +(cdef)/gab/++入栈
( c ∗ d − e ∗ f ) / g (c*d-e*f)/g (cdef)/g+ab/((入栈
c ∗ d − e ∗ f ) / g c*d-e*f)/g cdef)/g+(ab/cc加入到后缀表达式
∗ d − e ∗ f ) / g *d-e*f)/g def)/g+(ab/c*栈顶为(,*入栈
d − e ∗ f ) / g d-e*f)/g def)/g+(*ab/cdd加入到后缀表达式
− e ∗ f ) / g -e*f)/g ef)/g+(*ab/cd--优先级低于栈顶的*,弹出*
− e ∗ f ) / g -e*f)/g ef)/g+(ab/cd*-栈顶为(-入栈
e ∗ f ) / g e*f)/g ef)/g+(-ab/cd*ee加入到后缀表达式
∗ f ) / g *f)/g f)/g+(-ab/cd*e**优先级高于栈顶的-,*入栈
f ) / g f)/g f)/g+(-*ab/cd*eff加入到后缀表达式
)/g+(-*ab/cd*ef)把栈中(前面的的符号依次加入表达式
/g+ab/cd*ef*-//的优先级高于栈顶的+,/入栈
g+/ab/cd*ef*-gg加入到后缀表达式
+/ab/cd*ef*-g扫描完毕,把剩下的运算符依次加入表达式
ab/cd*ef*-g/+转换完成

最后的结果 a b / c d ∗ e f ∗ − g / + ab/cd*ef*-g/+ ab/cdefg/+ 就是要找的后缀表达式,可以自己那手工转换的来对比验证一下,结果肯定是一样的。


上面这一题碰巧没有遇到优先级相同的情况,下面我们来示范一个遇到优先级相同的情况下,该怎么做。

为了运算方便,我们定义了如下的优先级(具体数值没有关系,只是想表达优先级高低),我们把还没进栈的优先级表示为icp(栈外优先,in coming priority),把进栈后的运算符优先级表示为isp(栈内优先,in stack priority)

(* 和 /+ 和 -)
isp1536
icp6421

中缀表达式: a + b − a ∗ ( ( c + d ) / e − f ) + g a+b-a*((c+d)/e-f)+g a+ba((c+d)/ef)+g

待处理序列后缀表达式当前扫描元素动作
a + b − a ∗ ( ( c + d ) / e − f ) + g a+b-a*((c+d)/e-f)+g a+ba((c+d)/ef)+gaa加入到后缀表达式
+ b − a ∗ ( ( c + d ) / e − f ) + g +b-a*((c+d)/e-f)+g +ba((c+d)/ef)+ga++入栈
b − a ∗ ( ( c + d ) / e − f ) + g b-a*((c+d)/e-f)+g ba((c+d)/ef)+g+abb加入到后缀表达式
− a ∗ ( ( c + d ) / e − f ) + g -a*((c+d)/e-f)+g a((c+d)/ef)+g+ab-icp(’-’)低于isp(’+’),弹出+
− a ∗ ( ( c + d ) / e − f ) + g -a*((c+d)/e-f)+g a((c+d)/ef)+gab+--入栈
a ∗ ( ( c + d ) / e − f ) + g a*((c+d)/e-f)+g a((c+d)/ef)+g-ab+aa加入到后缀表达式
∗ ( ( c + d ) / e − f ) + g *((c+d)/e-f)+g ((c+d)/ef)+g-ab+a**的优先级高于栈顶的-,*入栈
( ( c + d ) / e − f ) + g ((c+d)/e-f)+g ((c+d)/ef)+g-*ab+a((的优先级高于*,(入栈
( c + d ) / e − f ) + g (c+d)/e-f)+g (c+d)/ef)+g-*(ab+a(icp(’(’)高于isp(’(’),(入栈
c + d ) / e − f ) + g c+d)/e-f)+g c+d)/ef)+g-*((ab+ac加入到后缀表达式
+ d ) / e − f ) + g +d)/e-f)+g +d)/ef)+g-*((ab+ac++入栈
d ) / e − f ) + g d)/e-f)+g d)/ef)+g-*((+ab+acdd加入到后缀表达式
) / e − f ) + g )/e-f)+g )/ef)+g-*((+ab+acd)(前面的运算符依次加到表达式中
/ e − f ) + g /e-f)+g /ef)+g-*(ab+acd+//入栈
e − f ) + g e-f)+g ef)+g-*(/ab+acd+ee加入到后缀表达式
− f ) + g -f)+g f)+g-*(/ab+acd+e--的优先级低于栈顶的/,弹出/
− f ) + g -f)+g f)+g-*(/ab+acd+e/--入栈
f ) + g f)+g f)+g-*(-ab+acd+e/ff加入到后缀表达式
) + g )+g )+g-*(-ab+acd+e/f)(前面的运算符依次加到表达式中
+g-*ab+acd+e/f-++的优先级低于栈顶的*,弹出*
+g-ab+acd+e/f-*+icp(’+’)低于isp(’-’),弹出-
+gab+acd+e/f-*-++入栈
g+ab+acd+e/f-*-gg加入到后缀表达式
+ab+acd+e/f-*-g扫描完毕,把剩下的运算符依次加入表达式
ab+acd+e/f-*-g+转换完成

通过两道例题,相信能比较好的理解中缀表达式是怎么转换成后缀表达式的了吧


代码实现
#include <iostream>
#include <stack>
#include <unordered_map>
using namespace std;

unordered_map<char, int>isp = {{'(', 1}, {'*', 5}, {'/', 5},
                                {'+', 3}, {'-', 3}, {')', 6}};
unordered_map<char, int>icp = {{'(', 6}, {'*', 4}, {'/', 4},
                               {'+', 2}, {'-', 2}, {')', 1}};

/**
 * 判断c是否是[a-zA-Z]之间的数
 * @param c 需要判断的字符
 * @return 是否是操作数
 */
bool op(char c){
    if (c >= 97 && c <= 122)
        return true;
    if (c >= 65 && c <= 90)
        return true;
    return false;
}

string in2post(string infix){
    // 后缀表达式
    string postfix;
    int inLen = infix.length();
    char curChar;
    char topCHar;
    stack<char> stack;

    for (int i = 0; i < inLen; ++i) {
        // 获取当前字符
        curChar = infix[i];
        // 如果是数字则加入到后缀表达式中
        if (op(curChar)){
            postfix += curChar;
            continue;
        }
        // 如果是运算符,则要进行判断
        else{
            // 如果栈为空,则直接把运算符压入栈
            if (stack.empty())
                stack.push(curChar);
            else{
                topCHar = stack.top();
                // 如果当前运算符比栈顶的运算符优先级高,则入栈
                if (icp[curChar] > isp[topCHar])
                    stack.push(curChar);
                // 如果当前运算符比栈顶的运算符优先级低并且不是右括号 ) ,则要弹出栈顶的运算符,再入栈
                else if(icp[curChar] < isp[topCHar] && curChar != ')') {
                    do {
                        postfix += topCHar;
                        stack.pop();
                        // 如果栈为空了,直接退出循环
                        if (stack.empty())
                            break;
                        topCHar = stack.top();
                    }while (icp[curChar] < isp[topCHar]);
                    stack.push(curChar);
                }
                // 如果当前运算符是右括号 ),要把括号中的运算符依次弹出。
                else{
                    while (topCHar != '('){
                        postfix += topCHar;
                        stack.pop();
                        topCHar = stack.top();
                    }
                    stack.pop();
                }
            }
        }
    }

    // 待处理的序列已经处理完了,剩下的就是把栈中的运算符依次加到后缀表达式
    while (!stack.empty()) {
        postfix += stack.top();
        stack.pop();
    }
    return postfix;
}
int main(){
//    string infix = "a/b+(c*d-e*f)/g";
    string infix = "a+b-a*((c+d)/e-f)+g";
    string postfix = in2post(infix);
    cout << postfix << endl;
    return 0;
}
;