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

     中缀表达式的计算
                               (包含“+ - * / ^ ()”)
  这次的程序目的是要将一个中缀表达式转化为后缀表达式并计算,我用两个栈来实现这个功能,一个记录操作符,一个记录操作数,并采取一边转化一边计算的方法最后得出结果。但在这之前,必须先解决以下几个问题。

  

(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"等符号并判断优先级 别并用相应的计算方法即可,并不会导致程序过于复杂。
  • 11
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值