表达式求值基本构架

来源:互联网 发布:苹果电脑图片设计软件 编辑:程序博客网 时间:2024/05/19 00:11

转了一个大神的博客,如果大神看见了,勿怪,我想自己纪念一下,只是敬仰!大神的博客

两种情况:

1. 根据输入的算数表达式,如(56-20) /(4+2), 先转化为后缀表达式(逆波兰式)56#20#-4#2#+/  因为输入的数字有多位数的(56),所以数之间用#隔开,然后根据后缀表达式求值。

2.根据输入的算数表达式,直接进行求值。


对于情况1:

转化为后缀表达式时用到了一个符号栈,把后缀表达式存放到数组postExp中,根据后缀表达式求值时用到了一个运算数栈,运算完后,栈顶即为所求。

完整代码如下:

#include <iostream>  #include <stdio.h>  #include <string.h>  #include <algorithm>  #include <stack>  #include <queue>  using namespace std;    const int maxOp = 7;//符号的总数    struct  Pri      //设定运算符优先级  {      char ch;     //运算符      int pri;     //优先级  }lpri[] = {{'=', 0}, {'(', 1}, {'*', 5}, {'/', 5}, {'+', 3}, {'-', 3}, {')', 6}},   rpri[] = {{'=', 0}, {'(', 6}, {'*', 4}, {'/', 4}, {'+', 2}, {'-', 2}, {')', 1}};    int LeftPri(char op)//求左运算符op的优先级  {      for(int i = 0; i < maxOp; ++ i)          if(lpri[i].ch == op)              return lpri[i].pri;  }    int RightPri(char op)//求右运算符op的优先级  {      for(int i = 0; i < maxOp; ++ i)          if(rpri[i].ch == op)              return rpri[i].pri;  }    bool IsOp(char ch)//判断符号ch是否为运算符  {      if(ch == '(' || ch == ')' || ch == '+' || ch == '-' || ch == '*' || ch == '/')          return true;      return false;  }    int Precede(char op1, char op2) //op1和op2运算符优先级的比较结果  {      int lPri = LeftPri(op1);      int rPri = RightPri(op2);      if(lPri == rPri)          return 0;      else if(lPri < rPri)          return -1;      else          return 1;  }    void TransToPostExp(char* exp, char postExp[]) //将算数表达式exp转换成后缀表达式  {      stack<char>opStack;//运算符栈      opStack.push('=');// =入栈,其优先级最低      int i = 0;//后缀表达式字符指针      while(*exp != '\0')      {          if(!IsOp(*exp)) //如果不是运算符          {              while(*exp >= '0' && *exp <= '9')//是数字              {                  postExp[i ++] = *exp;                  exp ++;              }              postExp[i ++] = '#'; //用'#'表示一个数值串的结束,比如456#          }          else          {              int cmpPri = Precede(opStack.top(), *exp);              if(cmpPri == 0) //左右运算符优先级相等,也就是()这种情况              {                  opStack.pop();// '('退栈                  exp ++;              }              else if(cmpPri == -1) //栈顶运算符优先级低              {                  opStack.push(*exp);//入栈,符号栈栈顶始终是优先级最高的                  exp ++;              }              else  //栈顶运算符优先级高              {                  while(Precede(opStack.top(), *exp) == 1)//不断退栈                  {                      postExp[i ++] = opStack.top();                      opStack.pop();                  }                  //opStack.push(*exp);                  // exp ++;  一定要注意!不能这样写,因为有可能当前字符是')'              }          }      }      while(opStack.top() != '=')//exp扫描完毕,退栈到' = '为止      {          postExp[i ++] = opStack.top();          opStack.pop();      }      postExp[i] = '\0';//postExp表达式添加结束标识  }    void GetTwoFromStack(stack<double>& numStack, double& a, double& b)//从运算数栈中获取两个数,栈顶和次栈顶  {      a = numStack.top();      numStack.pop();      b = numStack.top();      numStack.pop();  }    float CalFromPostExp(char* postExp)//计算后缀表达式的值  {      stack<double> numStack;//运算数栈      double a, b;      while(*postExp != '\0')      {          switch(*postExp)          {          case '#':              break;          case '+':              GetTwoFromStack(numStack, a, b);//获取运算数栈的两个数              numStack.push(b + a);//进行运算,再压入运算数中              break;          case '-':              GetTwoFromStack(numStack, a, b);              numStack.push(b - a);              break;          case '*':              GetTwoFromStack(numStack, a, b);              numStack.push(b * a);              break;          case '/':              GetTwoFromStack(numStack, a, b);              if(a != 0)                  numStack.push(b / a);              else              {                  cout << "除0错误! " <<endl;                  exit(0);              }              break;          default: //处理数字字符              int n = 0;              while(*postExp >= '0' && *postExp <= '9')              {                  n = n * 10 + (*postExp - '0');                  postExp ++;              }              numStack.push(n);              break;          }          postExp ++; //继续处理字符      }      return numStack.top();  }    char exp[50];  char postExp[50];    int main()  {      while(cin >> exp)      {          cout << "中缀表达式为: " << exp <<endl;          TransToPostExp(exp, postExp);//将算数表达式转化为后缀表达式,比如输入(56-20)/(4+2) ,输出 56#20#-4#2#+/          cout << "后缀表达式为: " << postExp <<endl;          cout << "表达式的值为: " <<CalFromPostExp(postExp) << endl << endl;      }      return 0;  }  

及其容易出现错误的地方为void TransToPostExp(char* exp, char postExp[]) //将算数表达式exp转换成后缀表达式   这个函数中:

else  //栈顶运算符优先级高              {                  while(Precede(opStack.top(), *exp) == 1)//不断退栈                  {                      postExp[i ++] = opStack.top();                      opStack.pop();                  }                  //opStack.push(*exp);                  // exp ++;  一定要注意!不能这样写,因为有可能当前字符是')'              }  
一定要注意如果当前字符时')'时,它的右优先级是最低的,因为除了'('外的其它符号 + - * / 遇到它都得退出符号栈

不要把')'加入到符号栈中,opStack.push(*exp);

也不要直接忽略')'而继续扫描下一个字符,因为此时栈顶可能时'(',需要进行下一轮的比较,把'('出栈, 所以不能写 exp ++.

也就是说 这里需要特别考虑 当前字符是 ')'的情况


对于情况2:

用到了两个栈,符号栈和运算数栈,对输入的运算数表达式边扫描边求值。

完整代码(来来回回改了N多遍,  支持 ((((3+2))))这种情况) :

#include <iostream>  #include <stdio.h>  #include <string.h>  #include <algorithm>  #include <stack>  #include <queue>  using namespace std;    const int maxOp = 7;//符号的总数    struct  Pri      //设定运算符优先级  {      char ch;     //运算符      int pri;     //优先级  }lpri[] = {{'=', 0}, {'(', 1}, {'*', 5}, {'/', 5}, {'+', 3}, {'-', 3}, {')', 6}},   rpri[] = {{'=', 0}, {'(', 6}, {'*', 4}, {'/', 4}, {'+', 2}, {'-', 2}, {')', 1}};    int LeftPri(char op)//求左运算符op的优先级  {      for(int i = 0; i < maxOp; ++ i)          if(lpri[i].ch == op)              return lpri[i].pri;  }    int RightPri(char op)//求右运算符op的优先级  {      for(int i = 0; i < maxOp; ++ i)          if(rpri[i].ch == op)              return rpri[i].pri;  }    bool IsOp(char ch)//判断符号ch是否为运算符  {      if(ch == '(' || ch == ')' || ch == '+' || ch == '-' || ch == '*' || ch == '/')          return true;      return false;  }    int Precede(char op1, char op2) //op1和op2运算符优先级的比较结果  {      int lPri = LeftPri(op1);      int rPri = RightPri(op2);      if(lPri == rPri)          return 0;      else if(lPri < rPri)          return -1;      else          return 1;  }      void GetTwoFromStack(stack<double>& numStack, double& a, double& b)//从运算数栈中获取两个数,栈顶和次栈顶  {      a = numStack.top();      numStack.pop();      b = numStack.top();      numStack.pop();  }        double CalFromNumStack(stack<char>& opStack, stack<double>& numStack)  //从符号栈提取栈顶符号,利用运算数栈的栈顶和次栈顶进行计算,并把结果压入运算数栈中  {      double a, b;      char op = opStack.top();//运算符提取      opStack.pop();//退栈      GetTwoFromStack(numStack, a, b);//a,b为栈顶和次栈顶      switch(op)      {      case '+':          numStack.push(b + a);          break;      case '-':          numStack.push(b - a);          break;      case '*':          numStack.push(b * a);          break;      case '/':          numStack.push((b / a));          break;      }//switch  }    float CalFromExp(char* exp)  {      stack<char> opStack;//符号栈      opStack.push('=');//'='优先级最低      stack<double> numStack;//运算数栈      while(*exp != '\0')      {          if(!IsOp(*exp)) //如果不是运算符          {              int n = 0;//提取数字              while(*exp >= '0' && *exp <= '9')              {                  n = n * 10 + (*exp - '0');                  exp ++;              }              numStack.push(n);//把提取出来的数压入运算数栈          }          else          {              int cmpPri = Precede(opStack.top(), *exp);              if(cmpPri == 0)  // ')'遇到栈顶'('              {                  opStack.pop();                  exp ++;              }                else if(cmpPri == -1)// 栈顶运算符优先级小              {                  opStack.push(*exp);                  exp ++;              }              else  //栈顶运算符优先级大              {                  while(Precede(opStack.top(), *exp) == 1)                  {                      CalFromNumStack(opStack,numStack);                  }//while              }             // exp ++;//扫描下一个字符          }//当前字符是运算符      }        while(opStack.top() != '=')//千万不能忘了这个!!      {          CalFromNumStack(opStack,numStack);      }      return numStack.top();  }  char exp[50];  char postExp[50];    int main()  {      while(cin >> exp)      {          cout << "中缀表达式为: " << exp <<endl;          //TransToPostExp(exp, postExp);//将算数表达式转化为后缀表达式,比如输入(56-20)/(4+2) ,输出 56#20#-4#2#+/         // cout << "后缀表达式为: " << postExp <<endl;          cout << "表达式的值为: " <<CalFromExp(exp) << endl << endl;      }      return 0;  }  
及其容易出现错误的地方和情况1一样。



原创粉丝点击