第四次作业
问题分析
- 算式计算(注意优先级与负数)
- 命令行输入输出
计算
看了题目本来是一头雾水,后来看了大神推荐的前缀中缀后缀表达式才有了头绪,先转换,后计算。他人思路如下:
转换思路:将优先级高的运算甩在前面,同级先出现在前面。
具体实现:以后缀表达式为例。
1.初始化栈1(存储后缀表达式),栈2(运算符的中转站),从左到右扫描算式。
2.数字直接进1。
3.运算符进2,但是符号进去之前判断优先级.
3-1.如果栈里面高或者**相等**就弹出并压入1,继续比较。这样在表达式中优先级高的符号先出现,先运算。同级先出现,先进表达式。
3-2.如果栈为空,或者栈顶元素优先级或者为“(”,直接进2。
4.括号进2。
4-1.“(”直接进2。
4-2.“)”出现要把它们之间运算符全部弹出并进1,这样括号里面的运算也先进表达式,括号任务完成,可以不要了。
5.表达式扫描完以后,将2内元素依次弹出并压入1
计算方法:扫描后缀表达式(先进先扫)。
1.遇见数字进栈。
2.遇见运算符就把栈前两个元素拉出来运算,结果再进栈。
最后栈顶元素即为所得算式结果
举个例子 `1+2*(3+4)-5` 。后缀表达式:(栈底到栈顶)`1 2 3 4 + * + 5 - `按照运算规则就是`1+2*(3+4)-5`
接下来是自己的(对负数处理)
1.因为Scan得到的是队列,正好从左到右,所以选择转换成后缀
2.选择用队列而不是栈来存储后缀表达式,因为转换的时候只进不出而最后计算需要先进先扫,毫无疑问,队列更合适
3.想了下,出现负数有两种情况。
3-1.在算式开头,运算时把0压进栈,这样计算-a就相当于0-a。
3-2.在左括号右边,这样在输入“(”时,加一个判断,如果下一个元素为“-”,就把0压进后缀表达式。
代码
转换成后缀表达式
void Calculation::trans(queue<string>*s)
{
string c;
while (s->empty() == false)
{
//读取队列第一个元素
c = s->front();
//c为运算符时,先判断优先级,低活着平级先将栈顶元素弹出,再与新的栈顶元素比较,直到高于或者栈空或者“(”进入
if (c == "*" || c == "/")
{
while (sign.empty() == false && (sign.top() == "*" || sign.top() == "/"))
{
after.push(sign.top());
sign.pop();
}
sign.push(c);
s->pop();
}
if (c == "+" || c == "-")
{
while (sign.empty() == false && (sign.top() == "+" || sign.top() == "-" || sign.top() == "*" || sign.top() == "/"))
{
after.push(sign.top());
sign.pop();
}
sign.push(c);
s->pop();
}
//为括号时
if (c == "(")
{
//判断下一个元素是否为“-”是的话说明下个数是负数,后缀表达式压入0
sign.push(c);
s->pop();
if (s->front() == "-")
{
after.push("0");
}
}
//将括号间运算符弹出并压入后缀表达式,括号舍弃
if (c == ")")
{
while (sign.top() != "(")
{
after.push(sign.top());
sign.pop();
}
sign.pop();
s->pop();
}
//数字直接进栈
else if (isdigit(c[0]))
{
after.push(c);
s->pop();
}
}
//运算符全部进后缀表达式
while (sign.empty() == false)
{
after.push(sign.top());
sign.pop();
}
}
计算后缀表达式
double Calculation::count()
{
string c;
stringstream ss;
num.push(0);//考虑第一个数为负数
while (after.empty() == false)
{
double flag = 0;//存每次栈顶元素与下个元素运算结果
c = after.front();
//为运算符就把前两个元素弹出来参与运算,并将结果存入栈中
if (c == "+")
{
double a = num.top();
num.pop();
double b = num.top();
num.pop();
flag = b + a;
num.push(flag);
}
if (c == "-")
{
double a = num.top();
num.pop();
double b = num.top();
num.pop();
flag = b - a;
num.push(flag);
}
if (c == "*")
{
double a = num.top();
num.pop();
double b = num.top();
num.pop();
flag = b*a;
num.push(flag);
}
if (c == "/")
{
double a = num.top();
num.pop();
double b = num.top();
num.pop();
flag = b / a;
num.push(flag);
}
//数字直接存入栈中
else if (isdigit(c[0]))
{
double temp;
ss << c;
ss >> temp;
num.push(temp);
ss.clear();
}
after.pop();
}
//栈顶元素为最终运算结果
return num.top();
}
命令行
怎么说呢,现在还不是太懂,而且它坑了我很久,一开始运行了是这样的
之后我怎么改代码都没用,后来无意间少写了一句,运行之后还是输出了结果,我就知道不是代码的问题,我就重新建了一个项目,最后成功输出了,截屏如下:
意外状况
- 一开始写完代码传参直接归0。。。后来大神自愿接过这个烂摊子,先不传参,把代码理了理,其中左右括号一个中文输入,一个英文输入,这样的错误让我觉得很对不住他。但是运算结果还是有很多不正确,他就告诉我检查时把计算和转换分开检查,然后我就辛劳的开工了
- 由于看资料时把别人的话看漏了,就是转换成后缀,判断优先级,同级也要弹出。结果还以为别人的错了,自己有劳心劳力的把减法全部变成加上一个负数,除法变成乘上他的倒数,最后还是悻悻的改回来