后缀表达式,我们亦称其为逆波兰序数。在咱们编写计算器的时候,总会要用双栈模拟,进行计算。
本题所描绘的中缀转后缀,只是很简单的转。并不能达到写计算器的目的,本文在此只用于个人的基础巩固,以及浅层次的思考,帮助进行中缀表达式转后缀表达式的理解。
中缀表达式如1*2+(2-1),其运算符一般出现在操作数之间, 因此称为中缀表达式,也就是大家编程中写的表达式。编译系统不考虑表达式的优先级别,只是对表达式从左到右进行扫描, 当遇到运算符时, 就把其前面的两个操作数取出,进行运算操作。为达到上述目的, 就要将中缀表达式进行改写,变为后缀表达式, 如上面的表达式1*2+(2-1),就变为12*21-+。
后缀表达式中不含有括号,且后缀表达式中的操作数排列次序和中缀表达式完全相同,这是运算符的次序发生了变化。我们实现的时候,便需要特定的数据结构(栈:stack),进行实现。
其中的stack<char> op进行操作符的存储。string ans用来存放后缀表达式。
接下来简述算法思想:
1)如果是‘(’则直接压入op栈。
2)如果是‘)’,依次从op栈弹出运算符加到字符串ans的后面,直到遇到 '('。
3)如果不是括号,则比较扫描到的运算符与op栈顶的运算符。如果扫描的运算符优先级高于栈顶运算符的优先级,便把扫描到的运算符压入栈中。若扫描的运算符优先级低于栈顶运算符的优先级,就依次把栈中运算符弹出加到字符串ans末尾,直到遇到的运算符优先级低于扫描到的运算符或者栈空,并把扫描到的运算符压入栈中。
若扫描结束,则依次弹出添加到ans的末尾,便得到了后缀表达式。
代码如下:
#include<iostream>
#include<cstring>
#include<stack>
using namespace std;
int prior(char op) //运算符优先级
{
if(op == '+' || op == '-')
{
return 1;
}
else if(op == '*' || op == '/')
{
return 2;
}
return 0;
}
string middleToLast(string middle)
{
stack<char> op;
string ans;
for(int i = 0; i < middle.size(); i++)
{
char c = middle[i]; //记录当前扫描字符
if(c >= '0' && c <= '9')
{
ans.append(1, c); //如果是操作数,则直接添加到ans末尾
}
else
{
if(c == '(') //若遇到的是'('则直接压住栈中
{
op.push('(');
}
else
{
if(c == ')') //如果遇到的是')'
{
while(op.top() != '(') //没有遇到匹配的'('
{
ans.append(1, op.top()); //将栈顶运算符加到ans末尾
op.pop(); //将栈顶元素弹出
}
op.pop(); //遇到了匹配的 '(' 跳出循环,并把'('弹出
}
else
{
if(op.empty()) //如果栈空,直接压入当前运算符
{
op.push(c);
}
else
{
if(prior(c) > op.top()) //如果当前运算符优先级高于栈顶运算符
{
op.push(c); //把当前运算符压入op栈中
}
else
{
while( !op.empty() && prior(c) <= prior(op.top()) ) //若栈非空且当前运算符低于栈顶运算符优先级
{
ans.append(1, op.top()); //栈顶字符加入到ans末尾
op.pop(); //弹出栈顶运算符
}
op.push(c); //把当前运算符压入栈中
}
}
}
}
}
}
while( !op.empty() ) //若栈非空
{
ans.append(1, op.top()); //把栈顶运算符添加到ans末尾
op.pop(); //弹出栈顶运算符
}
return ans;
}
int main()
{
string mdata, res;
cin >> mdata;
res = middleToLast(mdata);
for(int i = 0; i < res.size(); i++)
{
cout << res[i] << " ";
}
return 0;
}