假设有一天赵地佐同学(名称纯属虚构,如有雷同,纯属巧合)拿着一道数据极其恐怖的四则运算题找到同班的张三同学,希望他在1s内能给出答案。这时最好的办法是什么呢?当然是不理他,可惜乐于探究的张三同学并不愿意放弃这个机会,于是他拿出了随身携带的笔记本电脑。
为了解决这个问题,让我们尽可能抽象一下四则运算的表达式:
ans=A+B/C+(D*E+F)*G
像上面这种符合人们认知习惯自然书写而成的数学表达式称为中缀表达式。但可惜的是,愚蠢的计算机无法直接识别这种表达式,这意味这我们必须做一些工作让计算机可以从左向右顺序计算并得出正确结果。
将中缀表达式转化为后缀表达式(逆波兰表达式)便是一种解决办法。
逆波兰式是一种将待计算量写在前, 把运算符写在后(通常是两数之后)的计算式,比如:
中缀表达式 | 逆波兰表达式 |
A + B | A B + |
A * B | A B * |
A +B * C | A B C * + |
A * ( B + C ) | A B C + * |
逆波兰式的求解过程可以用栈来实现。为了便于理解,举一个带数值的例子:
中缀表达式:6 * ( ( 5 + ( 2 + 3 ) * 8 ) + 3 )
首先,转化为逆波兰式: 6 5 2 3 + 8 * + 3 + *
计算过程如下:
首先,将前四个数依次入栈:
Top Of Stack ——————> | 3 |
2 | |
5 | |
6 |
然后,遇到第一个符号为加号,记录并弹出栈顶的两个元素,计算结果后压入栈中
Top Of Stack ——————> | 5 |
5 | |
6 |
继续操作,遇到便数字压入栈中,遇到符号,弹出栈顶两元素并压入其结果。
(特别提醒:在减法和除法的计算中,数字弹出顺序与其计算顺序刚好相反)
Top Of Stack ——————> | 288 |
计算完成,其结果为288。
简单了解计算原理后,开始快乐地写代码(代码以函数形式给出,方便搬运):
#include
#include
#include
#include
using namespace std;
string str;
long long calculate(string str)
{
int len=str.length(),pos=0;
stack sta;
char ch;
while(pos='0'&&str[pos]<='9')
{
long long temp=0;
while(str[pos]!=' '&&str[pos]!='.') temp=temp*10+(str[pos++]-'0');
sta.push(temp);
}
else if(str[pos]==' '||str[pos]=='.') pos++;
else if(str[pos]=='@') break;
else
{
ch=str[pos++];
int num1,num2;
num2=sta.top(); sta.pop();
num1=sta.top(); sta.pop();
switch(ch)
{
case '+': sta.push(num1+num2); break;
case '-': sta.push(num1-num2); break;
case '*': sta.push(num1*num2); break;
case '/': sta.push(num1/num2); break;
}
}
}
return sta.top();
}
int main()
{
getline(cin,str);
cout<
推荐一个大佬的博客(比我讲的清楚多了)中缀表达式转后缀表达式
整体思路仍然采用栈的方式 (以 3*(2+1)为例 )
准备工作:采用string类储存待转化的中缀表达式,并用两个栈储存记录数字与符号。
主要思想:
主要步骤:
具体实现代码:
#include
#include
#include
#include
using namespace std;
string TRANS_TO_POLISH(string str)
{
stack num_stack, operator_stack;
int len = str.length(), pos = 0;
while (pos < len)
{
if (str[pos] >= '0' && str[pos] <= '9')
{
long long temp = 0;
while (str[pos] >= '0' && str[pos]<='9') temp = temp * 10 + (str[pos++] - '0');
num_stack.push(to_string(temp));
}
else if (str[pos] == ' ' || str[pos] == '.') pos++;
else
{
char ch = str[pos++];
if (ch == '+')
{
while(!operator_stack.empty()&&(operator_stack.top()=="*"||operator_stack.top()=="/")) num_stack.push(operator_stack.top()),operator_stack.pop();
while(!operator_stack.empty()&&(operator_stack.top()=="+"||operator_stack.top()=="-")) num_stack.push(operator_stack.top()),operator_stack.pop();
operator_stack.push("+");
}
else if (ch == '-')
{
while(!operator_stack.empty()&&(operator_stack.top()=="*"||operator_stack.top()=="/")) num_stack.push(operator_stack.top()),operator_stack.pop();
while(!operator_stack.empty()&&(operator_stack.top()=="+"||operator_stack.top()=="-")) num_stack.push(operator_stack.top()),operator_stack.pop();
operator_stack.push("-");
}
else if (ch == '*')
{
while(!operator_stack.empty()&&(operator_stack.top()=="*"||operator_stack.top()=="/")) num_stack.push(operator_stack.top()),operator_stack.pop();
operator_stack.push("*");
}
else if (ch == '/')
{
while(!operator_stack.empty()&&(operator_stack.top()=="*"||operator_stack.top()=="/")) num_stack.push(operator_stack.top()),operator_stack.pop();
operator_stack.push("/");
}
else if (ch == '(') operator_stack.push("(");
else
{
while (operator_stack.top() != "(")
{
num_stack.push(operator_stack.top());
operator_stack.pop();
}
operator_stack.pop();
}
}
}
while (!operator_stack.empty()) { num_stack.push(operator_stack.top()); operator_stack.pop(); }
string ans = "";
while (!num_stack.empty()) ans = num_stack.top() + " "+ans, num_stack.pop();
return ans;
}
int main()
{
string str; getline(cin, str);
cout << TRANS_TO_POLISH(str);
return 0;
}