——下定决心开始行动后,你会发现问题并非有想象中的那么难,问题照样有理可寻。过程中也曾迷茫,甚至想放弃,但既然开始了总不能半途而废吧。
——时间挤一挤真的还是会有的。
( github链接 )
接下来的是我的解题思路:
1.因为我们输入的式子是中缀表达式,但对计算机来说中缀表达式却是很复杂的,因此计算表达式的值时,通常需要先将中缀表达式转换为前缀或后缀表达式,然后再进行求值。
因此我先将中缀表达式转变为前缀表达式。(过程中我参考了以下博客 参考博客 )。
(期间我在转换的前缀表达式的过程中,忘记了将括号剔除,导致了程序无法正常运行。。。在这上花了好多时间。)
2.转化成前缀表达式之后就可以开始计算了:
从右到左遍历表达式的每个数字和符号,遇到是数字就进栈,遇到的是符号,就将栈顶的两个数字出栈,进行运算,运算结果进栈,一直到最终获得结果。
3.其中让我最懵的就是对负数的判断处理,这也是我考虑了最久的问题,后来在同学的帮助下终于攻克了该难关。
如下是主要代码:
int Calculation::level(string c) //判断运算符号优先级
{
int q;
if(c=="+" || c=="-")
{
q=1;
}
if(c=="*" || c=="/")
{
q=2;
}
return (q);
}
bool Calculation::isOperator(string s) //判断是否是四则运算符号
{
if (s=="+" || s=="-" ||s== "*" ||s=="/")
return true;
else
return false;
}
double Calculation::output(queue<string> strs)
{
stack<string> ch; // 放队列strs的逆表达式
stack<string> s1; //运算符栈
stack<string> s2; //储存中间元素的栈
stack<string> ch1;//放前缀表达式的逆式子
stack<double> out; //放运算结果的栈
string temp;
while(!strs.empty()) // 将scan中返回的队列按逆序的方式压入栈ch中
{
ch.push(strs.front()) ;
strs.pop();
}
while(!ch.empty())
{
temp=ch.top();
ch.pop();
if(isOperator(temp))
{
ex:;
if(s1.empty())
{
s1.push(temp);
}
else if (s1.top() == ")")
{
s1.push(temp);
}
else if(level(temp)>=level(s1.top()))
{
s1.push(temp);
}
else
{
s2.push(s1.top());
s1.pop();
goto ex;
}
}
else if(temp=="(")
{
while(s1.top()!=")")
{
s2.push(s1.top());
s1.pop();
}
s1.pop();
}
else if(temp==")")
{
s1.push(temp);
}
else
{
s2.push(temp) ;
}
}
while(!s1.empty()) //栈s1不为空则把s1中剩下的所有元素压入栈s2中
{
s2.push(s1.top());
s1.pop();
}
// 此时已得到前缀表达式
while(!s2.empty()) //将前缀表达式的逆序逐个压入栈ch1中
{
ch1.push((s2.top())) ;
s2.pop();
}
while(!ch1.empty()) //开始计算
{
double x,y,z;
string symble;
symble=ch1.top(); //将栈顶元素赋给字符串
ch1.pop();
if(symble =="+")
{
x=out.top();
out.pop();
y=out.top();
out.pop();
z=x+y;
out.push(z);
}
else if(symble == "-")
{
x=out.top();
out.pop();
y=out.top();
out.pop();
z=x-y;
out.push(z);
}
else if(symble == "*")
{
x=out.top();
out.pop();
y=out.top();
out.pop();
z=x*y;
out.push(z);
}
else if(symble == "/")
{
x=out.top();
out.pop();
y=out.top();
out.pop();
z=x/y;
out.push(z);
}
else // 将字符串中的数字转成double型
{
stringstream stream;
double number;
stream<<symble;
stream>>number;
out.push(number);
stream.clear();
}
}
double num=0;
num=out.top();
out.pop();
return num;
}
实现效果:
收获:
1.cmd命令行对于我来说也是陌生的,因此参考资料(参考资料 ),通过查看资料自己对于命令行有了基础的了解。
2.这次的作业也让我对stack栈有所了解,能够比较熟练应用该数据结构。
3.运用sstream将字符串中的数字转为double型。(可参考资料 )