中缀,前缀,后缀表达式概念及栈实现
一、简介
1️⃣ 中缀表达式(Infix)
- 形式:运算符在两个操作数中间 <操作数><操作符><操作数>
- 人类最熟悉的形式,写数学题都这么写
- 需要括号来明确优先级
- 操作数也可以为表达式
比如
(3 + 4) * 53 + 4 * 2 // 注意:乘法优先a + b * c - d2️⃣ 前缀表达式(Prefix)→ 又叫 *波兰式(Polish Notation)*
- 形式:运算符在操作数前面
- 不需要括号!靠顺序就能确定计算顺序
- 由波兰逻辑学家 卢卡西维茨 提出
栗子
中缀:A + B * C → 前缀:+ A * B C中缀:(A + B) * (C - D) → 前缀:* + A B - C D3️⃣ 后缀表达式(Postfix)→ 又叫 *逆波兰式(Reverse Polish Notation, RPN)*
- 形式:运算符在操作数后面
- 也不需要括号
- 计算机最喜欢!用栈(stack)就能轻松计算
中缀:A + B * C → 后缀:A B C * +中缀:(A + B) * (C - D) → 后缀:A B + C D - *(3 + 4) * 5 转成后缀: 3 4 + 5 *二、中缀转前缀与后缀
A*B+C*D-E转为后缀
我们可以先用括号来方便查看{(A*B)+(C*D)}-E,优先运算两个乘号,即AB*,CD*。接着是加号最后是减号。
写成{(AB*)(CD*)+}E-
我们把括号去掉,就得到后缀AB*CD*+E-
读后缀表达式的技巧:从左往右读,遇到操作符就看操作符前面两个操作数,三者构成一种运算
A*B+C*D-E转前缀
比如{(2*3)+(5*4)}-9->{(*23)+(*54)}-9->{+(*23)(*54)}-9->-{+(*23)(*54)}9
去掉括号,-+*2 3*5 4 9
处理技巧:从右往左读,读到操作数就扔到栈里面,读到操作符就操作栈里面的两个操作数并pop与返回。
三、具体实现

我们用栈来存放操作符,通过解析中缀将其转化为后缀。
如图,目前栈内有一个加号一个乘号,你可能好奇已经读取到了A和B以及一个加法操作符,为什么不弹出+号进行运算呢?
这是因为我们必须遵循如果新入栈的操作符的优先级高于上一个入栈的操作符,那么上一个操作符就不应该被弹出!所以乘法会被压入栈里面。
为什么会有这个原则???🤔
我们再回想一下后缀操作符的特性,他的操作数都是在左边而操作符在最右边。
既然操作数都在左,那么一但右操作数被确定下来(如何确定?就是通过比较,栈顶的操作符的优先级大于新来的操作符,那么就能确定右操作数!),那么我们就能知道谁是操作符。
接着我们继续解析,将C放到后缀表达式里,然后到了减号。

减号并没有乘号的优先级高,说明右操作数已经没有关于与乘法同级的操作符,故我们将会弹出乘法把他放入表达式。
接着比较加法和减法,他们属于同一优先级,但是加法在左边,优先级更高,所以弹出加法放入表达式,将减法入栈。

接着继续往下解析,将D加到表达式中,比较乘法和减号,乘法优先级高,压入栈里面。接着解析E。
现在到了尾部,我们把栈里面的东西加入到表达式中即可!

很显然,我们并没有考虑到中缀表达式有括号的情况🤔
那么下面让我们来研究一下。
首先在数学表达式中,括号的作用是什么???
((A+B)*C-D)*E,来看这个栗子。
每一个小括号里面都可以看作一个独立的运算单元,也就是一个完整的中缀表达式!

先将两个括号入栈,读到一个操作数A,接着读到了加号,还记得我们之前怎么操作的吗?
我们之前会拿加号和栈顶的操作符比较优先级,如果优先级低于栈顶则弹出。
规则依然没变:我们用栈顶元素和要入栈的元素作比较,如果栈顶元素优先级高,那么就将其弹出。
我们继续。

当我们遇到一个右括号时,意味着上一个左括号功能结束。因此我们需要把括号间的操作符全部弹出,直到碰到一个左括号才停下来!。
(ps:这里的左括号和右括号不是开口方向,而是指的位置。如果难以理解,那直接理解为,当一对括号成功匹配时,那么就要弹出他们以及他们之间的操作符!)

接着操作就大差不差,来看看结果。

前缀表达式的实现和后缀大差不差,只是方向需要注意。
至于代码实现,咳咳· · · · · ·
都说到这个份上了,你不自己动手操作一下???
可恶!不能懒!!!

四、代码实现
#include<iostream>#include<string>#include<stack>using namespace std;//判断是操作数类型bool isOperand(char c){ return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');}//操作符优先级int precedence(char a){ if (a == '+' || a == '-') return 1; if (a == '*' || a == '/') return 2; return 0; // '(' '[' '{' 优先级最低}//判断是否为左括号bool isLeftBracket(char a){ if(a=='{'||a=='('||a=='[') return true; return false;}// ✅ 判断是否是右括号bool isRightBracket(char c) { return c == ')' || c == ']' || c == '}';}string Postfix(const string &exp){ stack<char> S; string res=""; for(int i=0;i<exp.length();i++){ if(exp[i]==' ')continue; if(isOperand(exp[i])){ res +=exp[i]; } else if(isLeftBracket(exp[i])){ S.push(exp[i]); } else if(isRightBracket(exp[i])){ while(!S.empty()&&!isLeftBracket(S.top())){ char k =S.top(); res +=k; S.pop(); } if (!S.empty()) S.pop(); // 弹出左括号 } else{ // 重点:循环弹出所有优先级 >= 当前的运算符! while (!S.empty() && !isLeftBracket(S.top()) && precedence(S.top()) >= precedence(exp[i])) { res += S.top(); S.pop(); } S.push(exp[i]); } } // 清空栈! while (!S.empty()) { res += S.top(); S.pop(); } return res;}
int main(){ char exp[1000]; cout<<"enter a opertion: "; cin.getline(exp,1000); string res = Postfix(exp); cout<<res; return 0;}燃尽了。。。。
部分信息可能已经过时









