计算器C++代码实现—— 中缀表达式的计算

来源:互联网 发布:win10的ps软件 编辑:程序博客网 时间:2024/05/16 00:49
     中缀表达式的计算
                               (包含“+ - * / ^ ()”)
  这次的程序目的是要将一个中缀表达式转化为后缀表达式并计算,我用两个栈来实现这个功能,一个记录操作符,一个记录操作数,并采取一边转化一边计算的方法最后得出结果。但在这之前,必须先解决以下几个问题。

  

(1)当遇见“+ - * /   ^”操作符时,压人栈之前,什么情况下该从栈里提取操作符计算;而且情况可能很复杂,很可能会导致代码过于冗长。

   

(2)当有括号时,由于括号的优先级最高,这时该如何处理;

   

(3)当遇到等号时,很可能符号栈里还有一些(一个或以上)操作符并没有处理,这时该如何判断。


(一)为解决第一个问题,我想了一个办法,就是写一个用来判断符号优先级的函数,我写这个函数是用来解决什么时候该从栈里提取操作符计算的,这里又有几点要说明的;


 (1)当遇见"+”“-"则从栈顶是“+ - * / 还是 ^”都应该要提取出来并进行计算。所以这时函数应把这种情况判为真。

 

 (2)当遇见"-”“/"则只有栈顶是“ * /  ^”时才提取出来并进行计算且函数应把这种情况判为真。其他判为假。


 (3) 当遇见"^”因为“^”优先级高,而且如计算2^2^3,应先算后面,所以这时无论栈顶是“+ - * / 还是 ^”都不应该计算先,而应该先暂时把"^"压人栈,所以这时函数应把这种情况判为假。


 (4)当遇见其他操作符时,无需进行优先级判断。或者若栈顶元素是其他操作符时,函数则将此种情况判错。

 还有为解决情况太多导致代码过长的问题,我也专门写了一个用来计算并能把并计算结果压人操作数栈的函数。


(二)对于第二个问题,只需在遇到“(”时将其压人栈,无需处理,等在当遇到“)”时才将“(”之上的操作符按从上到下依次提取出来并计算,且将“(”弹出栈即可


(三)当遇到“=”时,这时认为表达式结束,则与遇到括号类似,将栈里的符号按从上到下提取出来并计算,这时遇到的另外一个问题就是如何判断符号已经被提取完毕了,我认为这是必须的,因为提取完了还进行提取的话很有可能就会导致程序出错(内存泄露)不过这也很容易解决,只需要在程序刚开始时将"0"压人符号栈来进行接下来的判断即可。

 

   分析完毕后,下面就是我写的程序:


    #include<iostream>      using namespace std;      #include<stack>      #include<string>      #include<cmath>      bool prev(string s1,string s2 ){  //判断符号s1 与 s2 的优先级别的函数      if(s1=="^"||s1=="*"||s1=="/")          return true;      else if((s1=="+"||s1=="-")&&(s2=="+"||s2=="-"))          return true;          else          return false;      }            void result(string st,stack<double> &d){  // 计算结果的函数      double x=d.top ();d.pop();      double y=d.top ();d.pop() ;      double re;      if(st=="+")         re=y+x;      else if(st=="-")        re=y-x;      else if(st=="*")            re=y*x;      else if(st=="/")        re=y/x;      else if(st=="^")        re=pow(y,x);      cout<<y<<st<<x<<"="<<re<<endl;       d.push(re);      }            int main(){         string  opr,st;             //opr 为操作数或操作符,st 用来提取符号栈的符号      stack<double> d;            //用来记录计算结果的栈      stack<string> s;            //用来记录符号的栈      s.push("0");                //用来判断符号栈里是否还有还有符号,防止出错                  double x;                   //若opr为操作数,则用x表示       while (cin>>opr)       {                     if(opr=="+"||opr=="-"||opr=="*"||opr=="/")        {            st=s.top();            while(prev(st,opr))            {  result(st,d);               s.pop();               st=s.top();            }            s.push (opr);                    }        else if(opr=="^"||opr=="(")            s.push(opr);                else if(opr==")")        {            st=s.top();            while(st!="(")            {result(st,d);               s.pop();               st=s.top();            }            s.pop();        }                      else if(opr=="=")       {     st=s.top();            while(st!="0")            {result(st,d);               s.pop();               st=s.top();            }                  cout<<d.top()<<endl;        d.pop();       }         else        {          x=atof(const_cast<const char *>(opr.c_str()));//类型转换         d.push(x);        }                   }                  return 0;                  }  



案例:
 case1:1 - 0.5 ^ 2 ^ 0 + ( 2 - 1 ) =
  2^0=1
  0.5^1=0.5
  1-0.5=0.5
  2-1=1
  0.5+1=1.5
  1.5

 

  case2:2 + ( 0.5 + ( 2 - 1 ) ^ 2 * 2 ) * 0.5 =

  2-1=1
  1^2=1
  1*2=2
  0.5+2=2.5
  2.5*0.5=1.25
  2+1.25=3.25
  3.25


 case3:( 1 + ( 2 / 3 ) ^ 2 ^ 0 ) * 2 =

  2/3=0.666667
  2^0=1
  0.666667^1=0.666667
  1+0.666667=1.66667
  1.66667*2=3.33333
  3.33333

 

通过上面三个案例,经检验,无论是计算次序还是计算结果都没有错,说明我的设计是正确的,但我的程序有两个比较大的缺陷


 (1)没有设置判断输入表达式错误的情况,所以必须给出正确的表达式才能进行正确的计算,如给出错误的表达式,本应该给出报错的,但还是会进 行计算,可惜因为输入情况错误的情况过多,判断起来过于复杂,所以我就没有进行判断。


 (2)输入的时候太麻烦,因为每次输入一个操作符或操作数时,都要空格,这是因为string的限制,我暂时也没有想到好的办法解决这个问题

 
 不过,我认为我的程序也有一个很大的优点,那就是易于推广,如要进行对数或三角数的计算,只需加入"log" "sin"等符号并判断优先级 别并用相应的计算方法即可,并不会导致程序过于复杂。
6 0
原创粉丝点击