【问题描述】
从标准输入中读入一个整数算术运算表达式,如24 / ( 1 + 2 + 36 / 6 / 2 - 2) * ( 12 / 2 / 2 )= ,计算表达式结果,并输出。
要求:
1、表达式运算符只有+、-、*、/,表达式末尾的=字符表示表达式输入结束,表达式中可能会出现空格;
2、表达式中会出现圆括号,括号可能嵌套,不会出现错误的表达式;
3、出现除号/时,以整数相除进行运算,结果仍为整数,例如:5/3结果应为1。
4、要求采用逆波兰表达式来实现表达式计算。
【输入形式】
从键盘输入一个以=结尾的整数算术运算表达式。操作符和操作数之间可以有空格分隔。
【输出形式】
在屏幕上输出计算结果(为整数,即在计算过程中除法为整除)。
【样例输入】
24 / ( 1 + 2 + 36 / 6 / 2 - 2) * ( 12 / 2 / 2 ) =
【样例输出】
18
【样例说明】
按照运算符及括号优先级依次计算表达式的值。
本问题的难点在于将中缀表达式转换成为后缀表达式(逆波兰表达式),我也是参考了若干文章,放在下面,需要自取:
前缀、中缀、后缀表达式(逆波兰表达式)
前缀表达式(波兰式),中缀表达式与后缀表达式(逆波兰式)
【数据结构与算法】逆波兰表达式、波兰表达式
利用后缀表达式求值:
遇到数字时,将数字压入堆栈,遇到运算符时,弹出栈顶的两个数,用运算符对它们做相应的计算(次顶元素op 栈顶元素 ),并将结果入栈
重复上述过程直到表达式最右端,最后运算得出的值即为表达式的结果
示例:
计算后缀表达式的值:1 3 2 - 4 × +
(1)从左至右扫描,将1,3,2压入栈
(2)遇到-运算符,2和3弹出,计算3-2(这里注意不是2-3,是次顶元素 op 栈顶元素,所以是3-2,下面步骤的求值同理)的值,得到1,将1压入栈
(3)遇到4,将4压入栈
(4)遇到×运算符,弹出4和1,计算1×4的值,得到4,将4压入栈
(5)遇到+运算符,弹出4和1,计算1+4的值,得到5即为最终结果
我的理解
将中缀表达式中表示运算先后顺序的括号转换成了先后顺序,也就是说后缀表达式中越靠前运算的优先级越高。在计算的时候,每遇见一个操作符(+, -, *, /),都会与前两个数字进行相应运算,直到最后。
下面是我的具体实现思路:
代码分成两大个模块,第一个是将输入的字符串转换为后缀表达式(逆波兰表达式),第二个是对第一个模块中产生的后缀表达式进行计算。得出最后的结果。
在第一个模块中,主要在函数:
vector<int> rpn(string &s);
中实现,传入的参数就是输入进来的字符串(中缀表达式),返回值是一个int类型的vector,保存中缀表达式中的数字。在进行转化时,创建两个stack s1, s2;分别表示符号栈、后缀表达式的字符栈。由于输入进的算式中的数字可能不是一位数,那么在s2中我才用一个’d’表示这个位置上是一个数字,并将对应的数字保存进vector中。
从左往右遍历输入的字符串,当遇到字符表示数字的时候,继续往后读,直到遇见非数字的字符,利用atoi函数将该字符串转换为int型后push_back在vector num,同时在后缀表达式字符栈s2中push一个’d’表示该位置是一个数字(digital);当遇见’(’时,直接将其push进s1符号栈;当遇到操作符(’+’, ’-’, ’*’, ’/’)时,当s1不为空时,将s1栈顶元素push到s2,直到遇见’*’, ’/’,因其二者优先级较高;当遇见’)’时,将s1中栈顶元素除了括号外都push到s2,直到遇见’(’;当遇到’=’时,表示运算式子已经读取完毕,这时候将s1符号栈中元素全部push到s2后,即可得到后缀表达式。
在第二个模块中,只要以函数:
int calculate(string &s, vector<int> &num)
为主,参数为第一个模块产生的后缀表达式和数字队列,返回值为运算结果。在此函数中,创建一个stack res;表示中间的计算结果。在遍历后缀表达式时,如果遇到’d’表示一个数字,那么将num中对应位置的数据push到res中;如果遇见操作符,那么将res中栈顶两个元素pop出来进行相应的计算,并将结果push到res中。当后缀表达式遍历完成时,res中将只有一个元素即为结果。
完整的代码如下:
#include <bits/stdc++.h>
using namespace std;
vector<int> rpn(string &s)
{
stack<char> s1, s2;
vector<int> num;
unsigned n = s.length();
for (unsigned i = 0; i < n && s[i] != '='; i++)
{
if (isdigit(s[i]))
{
string tmp;
tmp += s[i];
while (isdigit(s[++i]))
tmp += s[i];
num.push_back(atoi(tmp.c_str()));
s2.push('d'); //'d'表示此位置为一个数字
i--;
}
else if (s[i] == '(')
s1.push(s[i]);
else if (s[i] == '+' || s[i] == '-' || s[i] == '*' || s[i] == '/')
{
while (!s1.empty() && (s1.top() == '*' || s