算数四则混合运算表达式求值

简介: 算数四则混合运算表达式求值

算数混合四则运算求值


  • [问题]


利用算符优先关系,实现对算术四则混合运算表达式的求值


[要求]

输入的形式:表达式,例如2*(3+4)


包含的运算符只能有’+’ 、‘-’ 、‘*’ 、‘/’ 、‘(’、 ‘)’;


输出的形式:运算结果,例如2*(3+4)=14;


程序所能达到的功能:对表达式求值并输出


思路:利用栈实现表达式求值,需要思考如下问题:

算符的优先级


字符转换成数字(包括解析小数)


主要思路:

算术表达式有三种类型:前缀,中缀,后缀表达式,而这里主要利用的是中缀和后缀表达式


示图:


中缀表达式:运算符位于操作数中间

中缀表达式的运算规则:“先乘除,后加减,从左到右计算,先括号内,后括号外”


即中缀表达式不仅要依赖运算符优先级,而且还要处理括号


后缀表达式:运算符在操作数的后面

已考虑了运算符的优先级,而且越放在前面的运算符来越优先执行


没有括号,只有操作数和运算符


我们平常使用的是中缀表达式,而后缀表达式运算的优先已经好了,所以我们用后缀表达式进行四则计算


步骤一:中缀表达式转后缀表达式


示图:



过程实现:

遍历中缀表达式


遇到数字直接放入后缀表达式


遇到左括号入栈


遇到右括号则将栈里的运算符一直出栈到左括号出栈,并按出栈顺序放入后缀表达式中(达到一个去括号的效果)


遇到 * / 运算符,因为是较高优先级运算符,所以直接入栈


遇到 + - 运算符,因为是较低优先级运算符,所以需要先将栈顶高于或等于其优先级的运算符 * / 给出栈并放入后缀表达式中(遇到左括号需要停止)


遇到其他字符则直接报错退出程序


当遍历完后再将栈中剩余的运算符给出栈并放入后缀表达式中


步骤二:依靠后缀表达式计算结果

因为后缀表达式已经达到去括号,决定运算符优先级的效果了,所以可以直接计算


示图:


过程实现:

遍历后缀表达式


遇到数字直接入栈


遇到运算符则将栈顶出栈,取出两个操作数(注:左操作数是第二个出栈的数值)


根据操作符将两操作数进行运算得到得结果给入栈到栈中


遍历结束后,栈顶的数据就是最后的结果


思考:

优先级:后缀表达式已经将运算符的优先级给处理好了


字符转浮点:从中缀表达式转后缀时,遍历到数字或小数点则一直进行放入到后缀表达式中,并在最后放一个空格做分隔符,处理后缀表达式时遇到数字就依靠分隔符确定区间并转成浮点数


实现代码:


#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
#include<string>
#include<stack>
#include <stdlib.h>
using namespace std;
string TransExpToPostexp(string& exp)
{
  stack<char> optr;
  string postexp;
  for (int i = 0; i < exp.size(); i++)
  {
    if ((exp[i] >= '0' && exp[i] <= '9') || exp[i] == '.')//是数字直接进字符串
    {
      postexp += exp[i];
      while ((exp[i+1] >= '0' && exp[i+1] <= '9') || exp[i+1] == '.')
        postexp += exp[++i];
      postexp += ' ';//分隔
    }
    else
    {
      if (exp[i] == '(')//是左括号进栈
        optr.push(exp[i]);
      else if (exp[i] == ')')//遇到右括号则出栈到左括号出栈
      {
        while (!optr.empty())
        {
          if (optr.top() == '(')//遇到左括号则出栈并退出
          {
            optr.pop();
            break;
          }
          else//遇到其他操作符则添加到后缀表达式中并出栈
          {
            postexp += optr.top();
            postexp += ' ';//分隔
            optr.pop();
          }
        }
      }
      else if (exp[i] == '*' || exp[i] == '/')
      {
        optr.push(exp[i]);
      }
      else if (exp[i] == '-' || exp[i] == '+')
      {
        while (!optr.empty()&&optr.top()!='(')//小于等于栈顶操作符数据,则出栈*
        {
          postexp += optr.top();
          postexp += ' ';//分隔
          optr.pop();
        }
        //进栈
        optr.push(exp[i]);
      }
      else//表达式错误
      {
        perror("exp error!");
        exit(1);
      }
    }
  }
  //遍历结束,剩余操作符出栈
  while (!optr.empty())
  {
    postexp += optr.top();
    postexp += ' ';//分隔
    optr.pop();
  }
  return postexp;
}
double Calculate(string postexp)
{
  stack<double> data;//数据栈
  for (int i = 0; i < postexp.size(); i++)
  {
    if (postexp[i] >= '0' && postexp[i] <= '9')//是数字则入栈
    {
      int left = i, right = i;
      while (postexp[right] != ' ')
        right++;
      double num = atof(postexp.substr(left,right).c_str());//字符串转浮点
      //cout << num << endl;
      data.push(num);
      i = right;
    }
    else//遇到操作符
    {
      //取栈顶两数据,注意先后顺序,后一个才是左操作数
      double right = data.top(); 
      data.pop();
      double left = data.top(); 
      data.pop();
      //判断操作符,得到数据再入栈
      char optr = postexp[i];
      switch (optr)
      {
      case '+':
        data.push(left + right);
        break;
      case '-':
        data.push(left - right);
        break;
      case '*':
        data.push(left * right);
        break;
      case '/':
        data.push(left / right);
        break;
      default:
        perror("optr error");
        break;
      }
      cout << data.top() << endl;
      i++;
    }
  }
  return data.top();
}
int main()
{
  string str;
  while (cin >> str)
  {
    string postexp=TransExpToPostexp(str) ;
    cout << postexp << endl;
    cout << Calculate(postexp) << endl;
  }
  return 0;
}
相关文章
|
6月前
|
存储 编译器 C语言
【表达式求值】整型提升和算术转换
【表达式求值】整型提升和算术转换
53 0
|
5月前
|
C语言
C语言中的赋值运算、比较运算和逻辑运算详解
C语言中的赋值运算、比较运算和逻辑运算详解
|
5月前
|
Go
go算数运算、关系运算、布尔运算、位运算
go算数运算、关系运算、布尔运算、位运算
|
人工智能 Shell
if 运算表达式
if 运算表达式
61 1
|
存储 算法
逆波兰表达式:计算包含括号的四则运算表达式
平时我们进行数学计算使用的常见书写方式就是中缀表达式,即每一个运算符号都位于计算数的中间,如下: (1+2)\3 而这对于计算机进行求取结果来说,并不是一个最优的方案。
120 0
|
JavaScript 前端开发
|
数据库
关系代数运算——除法运算
关系代数运算——除法运算
267 0
关系代数运算——除法运算
|
存储 C语言
位操作符的一些运算小技巧
位操作符的一些运算小技巧
104 0
算数运算
算数运算
133 0