后缀表达式,我们亦称其为逆波兰序数。在咱们编写计算器的时候,总会要用双栈模拟,进行计算。
本题所描绘的中缀转后缀,只是很简单的转。并不能达到写计算器的目的,本文在此只用于个人的基础巩固,以及浅层次的思考,帮助进行中缀表达式转后缀表达式的理解。
中缀表达式如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; }