第四次作业

github链接地址

问题分析

  • 算式计算(注意优先级与负数)
  • 命令行输入输出

计算

看了题目本来是一头雾水,后来看了大神推荐的前缀中缀后缀表达式才有了头绪,先转换,后计算。他人思路如下:

转换思路:将优先级高的运算甩在前面,同级先出现在前面。

具体实现:以后缀表达式为例。
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。。。后来大神自愿接过这个烂摊子,先不传参,把代码理了理,其中左右括号一个中文输入,一个英文输入,这样的错误让我觉得很对不住他。但是运算结果还是有很多不正确,他就告诉我检查时把计算和转换分开检查,然后我就辛劳的开工了
  • 由于看资料时把别人的话看漏了,就是转换成后缀,判断优先级,同级也要弹出。结果还以为别人的错了,自己有劳心劳力的把减法全部变成加上一个负数,除法变成乘上他的倒数,最后还是悻悻的改回来
posted @ 2016-04-13 16:48  抱朴  阅读(138)  评论(1编辑  收藏  举报