数据结构:c++算术表达式求值

算术表达式求值

[问题描述]  一个算术表达式是由操作数(operand)、运算符(operator)和界限符(delimiter)组成的。假设操作数是正实数,运算符只含加减乘除等四种运算符,界限符有左右括号和表达式起始、结束符“#”,如:#(7+15)*(23-28/4)#。引入表达式起始、结束符是为了方便。编程利用“运算符优先法”求算术表达式的值。

解题思路
1.首先建立两个栈用来分别存储操作数(operand)以及运算符(operator),为了减少代码量就直接调用STL中的栈方法来对“入栈”“出栈”以及“访问栈顶元素”进行操作。
2.最重要的一点是“如何才能使表达试正确遵循运算法则”(先乘除后加减,先算括号内的再处理括号外的),这就涉及到运算符优先级的问题,即在 Precede()方法中用二维数组定义好运算符的优先关系,然后根据方法返回的结果进行不同的操作。
3.最后是关于输入问题,操作数和运算符都只用字符型来输入,然后通过字符的ASCII码值来区分是是操作数还是运算符,然后正确进栈。

下面直接上代码,代码中有详细解释

#include
#include
#include
using namespace std;
stack<char>OPTR;
stack<double>OPND;
typedef struct {//因为在输入表达式时是一个一个的输入字符,而操作数若长度大于2则无法正确得到操作数,因此该结构是用来存储一个完整的字符数,便于在CharTOInt()中将其转换为数字
 char data[10];
 int length;
}haha;
bool In(char ch)//判断输入的是不是运算符,若是则返回true
{
 if (ch == '+' || ch == '-' || ch == '*' || ch == '/' || ch == '(' || ch == ')'||ch=='#')
 {
  return true;
 }
 else return false;
}
char Precede(char x, char y)//运算符优先级的判断
{
 int ang[2];
 char opnd[2] = { x,y };
 char aa[7][7] = {
     {'>','>','<','<','<','>','>'},
     {'>','>','<','<','<','>','>'},
     {'>','>','>','>','<','>','>'},
     {'>','>','>','>','<','>','>'},
     {'<','<','<','<','<','=',' '},
     {'>','>','>','>',' ','>','>'},
     {'<','<','<','<','<',' ','='}
 };
 for (int z = 0; z < 2; z++)
 {
  switch (opnd[z])
  {
  case '+':ang[z] = 0;
   break;
  case '-':ang[z] = 1;
   break;
  case '*':ang[z] = 2;
   break;
  case '/':ang[z] = 3;
   break;
  case '(':ang[z] = 4;
   break;
  case ')':ang[z] = 5;
   break;
  case '#':ang[z] = 6;
   break;
  }
     }
 return aa[ang[0]][ang[1]];
}
double Operate(double a, char theta, double b)//加减乘除运算
{
 double result;
 switch (theta)
 {
 case '+': result=a + b;
       break;
 case '-':result= a - b;
       break;
 case '*':result= a * b;
       break;
 case '/':result= a / b;
       break;
  }
 return result ;
}
double charTOint(haha cunchu)//将字符数字转换成一个完整的数字型数字
{
 int point=0;//用来判断是否有小数点以及小数点的位置
 double result=0;
 
 for (int i = 0; i < cunchu.length; i++)//先找出小数点的位置
 {
  if (cunchu.data[i] == '.')
   break;
     ++point;
    }
 for (int i=0,j = 0; i < cunchu.length; i++)//根据结构中的length以及小数点位置可以正确转换数字
 {
  if (i != point)//小数点不放入计算
  {
   result += (cunchu.data[i] - '0')*pow(10, point - j - 1);
   j++;
  }
 }
 return result;
}
double EvaluateExpression()//最关键的方法
{
 bool flag = true;//用来判断是否输入一个数字完毕,输入完毕则转化为数字型,存入栈中
 haha cunchu;//用来记录每个数字字符,然后转换为数字计算
 OPTR.push('#');//将表达式起始符压入栈中,用于判断是否该结束循环
 char ch;
 int i=0;
 char theta;//记录弹出来的运算符
 double a, b;//记录弹出来的操作数
 cout<<"请输入正确的表达式,以'#'结束"<<endl;
 cin >> ch;
 cunchu.length = 0;
 while (ch != '#' || OPTR.top() != '#')//就算ch=='#'也不一定停止循环,因为OPTR中可能还有加减乘除需要运算
 {
  if (!In(ch))
  {
    cunchu.data[i] = ch;
    ++i;
    ++cunchu.length;
    flag = true;
    cin >> ch;
  }
  else {
   if (flag)//这判断非常重要,是操作数正确进栈关键方法。思路:即当输入运算符时,表明运算符的前一个操作数已经输入完毕,此时可以将结构存储的数字字符转换成double型,并将数字进入OPND栈
   {
    OPND.push(charTOint(cunchu));//字符转换数字
    cunchu.length = 0; i = 0;//所有回到初始化,用以记录下一个数字
    flag = false;//操作数进栈成功后必须将flag取反,因为当操作数进栈后,它在switch中,若进行case '>'时,此时的ch操作符是还没进栈的,ch还需再次进入while循环,判断ch与OPTR栈顶操作符比较优先级,
                 //再决定ch的情况。正因为ch还需进入while循环,所以在此之前需将flag=false,否则flag=true,又会执行OPND.push(charTOint(cunchu)),这时是将数字0进栈,将会导致运算出错
   }
   switch (Precede(OPTR.top(), ch))
   {
       case '>': { theta = OPTR.top();OPTR.pop();  //如果栈顶运算符优先级较大,则取OPND栈顶两个数以及OPTR栈顶运算符进行运算,结果再入栈
                   b= OPND.top(); OPND.pop();
                   a= OPND.top(); OPND.pop();
                   OPND.push(Operate(a, theta, b));//此处不用输入ch,是因为原值还没入栈,其优先级比较小,仍要跟下一个栈顶比较
                   break;
               }
       case '<': {
                   OPTR.push(ch);
                   cin >> ch;
                   break;
             }
       case '=': {
                 OPTR.pop();
                 cin >> ch;
                 break;
              }
        }
    }
 }
 return OPND.top();
}
int main()
{
  
 cout<<"结果:" EvaluateExpression();
}

运行结果

数据结构:c++算术表达式求值_第1张图片小白,第一篇博客勿喷。。。

你可能感兴趣的:(数据结构)