数据结构中一个重要内容就是中缀表达式求值,我们平常用的都是中缀表达式 如:2*(1+3)-4 、1+(3+2)*2 等等。之所以我们能快速得出答案,是因为我们知道计算的法则:从左往右,先乘除,后加减,括号最先计算。然而计算机并不懂这些,想要写段代码来让计算机也能计算,我们就必须先了解前缀,后缀表达式,以下是相关介绍及转换方法:
先来看两个例子
中缀表达式
2 *(1+3)- 4 、 9 /(1+2)+2 * (1+4)
前缀表达式
- * 2 + 1 3 4 、 + / 9 + 1 2 * 2 + 1 4
后缀表达式
2 1 3 + * 4 - 、 9 1 2 + / 2 1 4+ * +
看不懂没关系,现在来讲如何转换
(用上面例子的第二个进行讲解,懂得方法多练习即可)
中缀转前缀:
先将我们熟悉的中缀表达式 按照运算优先级关系 用括号括起来
(( 9 /(1+2))+(2 *(1 + 4)))
可以就看到,每个运算符都至少被一个运算符括着;
将每个运算符提到括着它的并且离它最近的括号前面;
提一个运算符,去一个括号;
初学者建议 从外往内,从左至右 ,下面是步骤:
1) +(9 /(1+2)) (2 *(1+4))
2) + / 9(1 +2 ) * 2(1+4)
3) + / 9 +1 2 * 2 +1 4
慢慢体会,之后稍加练习就能很熟练了
中缀转后缀
与转换前缀一样,先将我们熟悉的中缀表达式 按照运算优先级关系 用括号括起来
(( 9 /(1+2))+(2 (1 + 4)))
可以就看到,每个运算符都至少被一个运算符括着;
将每个运算符提到括着它的并且离它最近的括号后面;
提一个运算符,去一个括号;(还是从外往内,从左往右)
1)(9 / ( 1 + 2)) (2 * (1 +4 )+
2)9 (1 +2)/ 2 ( 1 + 4) +
3)9 1 2 + / 2 1 4 + * +
现在给几个练习
(1+3)*5 / 2 -(1+3) *2
前缀表达式 :- / * +1 3 5 2 * + 1 3 2
后缀表达式:1 3 + 5 * 2 / 1 3 + 2 * -
慢慢练习,之后就能像求中缀表达式一样得心应手了
学习了前缀表达式和后缀表达式的转换,接下来就来看看如何利用前缀表达式和后缀表达式求中缀表达式吧
以练习题为例
前缀表达式 :- / * +1 3 5 2 * + 1 3 2
1)从后往前遍历 表达式
2)遇到数字就入栈,遇到运算符就让两个元素出栈,
3)记 a=第一个出栈数,b 第二个·出栈数 ,则 c =a 运算符 b,再将 c 入栈,接着遍历下一个元素
4)遍历完后,栈只剩最后一个元素(栈顶元素)即为最终结果
后缀表达式:从前往后遍历表达式(与前缀表达式大同小异,不细讲,下面提供代码)
利用计算机求中缀表达式一般是利用后缀表达式(边转换,边求值)代码如下:
#include<iostream>
#include<stack>
#include<string>
using namespace std;
int oper(char a,int b,int c) //运算函数
{
switch(a)
{
case '+' : return (b + c); break;
case '-' : return (b - c); break;
case '*' : return (b * c); break;
case '/' : return (b / c); break;
}
}
int main()
{
stack<int>d; //存放数据栈
stack<char>c; //存放运算符栈
int a,b;
char s; //a,b,s 作运算函数的参数
string str;
cin>>str; //输入中缀表达式
for(int i=0;i<str.size();i++)
{
if(str[i]=='+'||str[i]=='-')
{
if(c.empty()) c.push(str[i]); //运算符为空栈时,直接入栈
else {
while(!c.empty()&&(c.top()=='+'||c.top()=='-'||c.top()=='*'||c.top()=='/')) //运算优先级大于等于‘+’‘-’
{
a=d.top();d.pop();
b=d.top();d.pop();
s=c.top();c.pop();
d.push(oper(s,b,a));
}
c.push(str[i]); //运算结束将str[i]入栈
}
}
else if(str[i]=='*'||str[i]=='/')
{
if(c.empty()||c.top()=='+'||c.top()=='-') c.push(str[i]); //运算符栈为空,栈顶为‘+’‘-’时,直接入栈
else{
while(c.top()=='*'||c.top()=='/')
{
a=d.top();d.pop();
b=d.top();d.pop();
s=c.top();c.pop();
d.push(oper(s,b,a));
}
c.push(str[i]);
}
}
else if(str[i]=='(') c.push(str[i]);
else if(str[i]==')')
{
while(c.top()!='(')
{
a=d.top(); d.pop();
b=d.top(); d.pop();
s=c.top(); c.pop();
d.push(oper(s,b,a));
}
c.pop(); // '('出栈
}
else
d.push(str[i]-'0');
}
while(!c.empty())
{
a=d.top(); d.pop();
b=d.top(); d.pop();
s=c.top(); c.pop();
d.push(oper(s,b,a));
}
cout<<d.top();
return 0;
}
学习前缀、后缀表达式的一个目的就是想利用计算机求解中缀表达式
以上代码牵扯运算符优先级,如不能理解,建议 去mooc 慕课 找浙江大学 陈越、何钦铭老师的 数据结构 课程,里面有更详细的介绍。