逆波兰计算器

Posted taming

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了逆波兰计算器相关的知识,希望对你有一定的参考价值。

对于我们数学中常见的中缀表达式如 1+2 我们能很好的理解和判断优先级,但对于编程而言就显得非常的繁琐,但可以转化为后缀表达式也就是逆波兰式如 1+2变成1 2 + ,这样一来编写程序来计算就变得容易起来,计算逆波兰式在计算机上主要是利用栈结构来存储,对于一个逆波兰式如 1 2 + 3 *,(本来的中缀表达式应该是(1+2)*3),计算过程如下:假设现在是用字符串存储的逆波兰式,从头到尾遍历一遍,是数字就入栈,是运算符就出栈两个数进行对应的运算后再入栈,到最后栈中只剩下一个元素也就是结果了。具体过程为:1入栈,2入栈,遇到 +,2出栈,1出栈,1+2 = 3入栈,3入栈,遇到 *,出栈 3,出栈 3,入栈3*3 = 9,结束。这里没用到减法和除法,这两种运算需要考虑运算顺序,是后出栈的数除或减先出栈的数。

 

逆波兰式的计算很简单,难的是在于将普通式转化为逆波兰式

直接记住转化规则:

如果是数字,直接打印这个数字

如果是左括号也就是‘(‘,直接入栈。

如果是‘)‘,一直出栈并打印直到遇到‘(‘,这里‘)‘不再入栈。

如果是‘+‘ 或 ‘-‘,一直出栈并打印直到遇到‘(‘或者到栈底的时候停止出栈,然后‘+‘或‘-‘入栈。

如果是‘*‘或‘/‘,一直出栈并打印直到遇到‘+‘或‘-‘或‘(‘或栈底停止出栈,然后‘*‘或‘/‘入栈。

当结束时若栈不为空,出栈并打印栈中全部元素

举个例:(1+2)*3/4转化为逆波兰式

首先‘(‘入栈,栈中为‘(‘,打印为空。

1直接打印,栈中为‘(‘,打印为1。

‘+‘因为栈底为‘(‘,不需要出栈任何元素直接入栈,栈中为‘(‘,‘+‘,打印为1。

2直接打印,栈中为‘(‘,‘+‘,打印为1  2。

‘)‘出栈并打印‘+‘,然后遇到‘(‘停止出栈,接着出栈掉‘(‘,栈中为空,打印为1  2  +。

‘*‘因为栈为空直接入栈,栈中为‘*‘,打印为1  2  +。

3直接打印,栈中为空,打印为1  2  +  3。

‘/‘出栈并打印‘/‘,然后遇到栈底,结束出栈,入栈‘/‘,栈中为‘/‘,打印为1  2  +  3  *。

4直接打印,栈中为栈中为‘/‘,打印为1  2  +  3  *  4。

结束时栈中还有‘/‘,出栈并打印,栈中为‘/‘,打印为1  2  +  3  *   4  /。

结果就为1  2  +  3  *   4  /

逆波兰表达式的计算

从头到尾遍历一遍逆波兰表达式,如果是数字就直接入栈,如果是运算符就出栈两个数进行运算后结果入栈。

当遍历完以后栈中所剩的一个数就是最终结果。

接着上例:

1, 2依次入栈。

+出栈1 2执行+然后结果3入栈。

3入栈。

* 出栈3 3进行*然后入栈结果9.

4入栈。

/出栈9 4进行/然后入栈9/4。

结果就是9/4=2.25。

最后贴上代码:

 

[cpp] view plain copy
 
  1. //因为是随手写来练习一下就不考虑小数和负数的情况了,那样会耽误很多时间  
  2. #include<iostream>  
  3. #include<cmath>  
  4. #include<string>  
  5. using namespace std;  
  6.   
  7. //虽然有现成的模板类stack但最后还是手写了一个  
  8. template<typename anytype>  
  9. class MyStack{  
  10.    struct element{  
  11.       anytype Data;  
  12.       element* last;  
  13.    };  
  14.    element* top;  
  15. public:  
  16.    MyStack():top(NULL){}  
  17.    ~MyStack(){  
  18.       element* pointer;  
  19.       while(top!=NULL){  
  20.          pointer=top;  
  21.          delete pointer;  
  22.       }  
  23.    }  
  24.    void push(anytype x){  
  25.       element* pointer=new element;  
  26.       pointer->Data=x;  
  27.       pointer->last=top;  
  28.       top=pointer;  
  29.    }  
  30.   
  31.    anytype pop(){  
  32.       if(top!=NULL){  
  33.          anytype PopData=top->Data;  
  34.          element* pointer=top;  
  35.          top=top->last;  
  36.          delete pointer;  
  37.          return PopData;  
  38.       }  
  39.       else{  
  40.          return 0;  
  41.       }  
  42.    }  
  43.    anytype GetTop(){  
  44.       if(top!=NULL){  
  45.          return top->Data;  
  46.       }  
  47.       else{  
  48.          return 0;  
  49.       }  
  50.    }  
  51. };  
  52.   
  53. //定于一个函数用于将普通表达式转化为逆波兰表达式  
  54. string change(string x){  
  55.    int len=x.size();  
  56.    string ans;  
  57.    MyStack<char> operators;  
  58.    for(int i=0;i<len;i++){  
  59.       if(x[i]>=‘0‘&&x[i]<=‘9‘){  
  60.          int j;  
  61.          for(j=i;x[j]>=‘0‘&&x[j]<=‘9‘;j++){  
  62.             ans+=x[j];  
  63.          }  
  64.          ans+=‘ ‘;  
  65.          i=j-1;  
  66.       }  
  67.       else if(x[i]==‘(‘){  
  68.          operators.push(x[i]);  
  69.       }  
  70.       else if(x[i]==‘*‘||x[i]==‘/‘){  
  71.          while(operators.GetTop()==‘*‘||operators.GetTop()==‘/‘){  
  72.             ans+=operators.pop();  
  73.          }  
  74.          operators.push(x[i]);  
  75.       }  
  76.       else if(x[i]==‘)‘){  
  77.          while(operators.GetTop()!=‘(‘){  
  78.             ans+=operators.pop();  
  79.          }  
  80.          operators.pop();  
  81.       }  
  82.       else if(x[i]==‘+‘||x[i]==‘-‘){  
  83.          while(operators.GetTop()!=‘(‘&&operators.GetTop()!=0){  
  84.             ans+=operators.pop();  
  85.             ans+=‘ ‘;  
  86.          }  
  87.          operators.push(x[i]);  
  88.       }  
  89.    }  
  90.    while(operators.GetTop()!=0){  
  91.       ans+=operators.pop();  
  92.       ans+=‘ ‘;  
  93.    }  
  94.    return ans;  
  95. }  
  96.   
  97. //随手写的一个将字符串存储的数字转化为整型数的函数 这里就不考虑小数负数的情况了  
  98. long long ToNum(string x){  
  99.    int len=x.size();  
  100.    long long ans=0;  
  101.    for(int i=0;i<len;i++){  
  102.       ans+=(x[i]-‘0‘)*pow(10.0,len-i-1)+0.5;//测试了几下pow函数可能会出现浮点数误差就四舍五入来保证精度  
  103.    }  
  104.    return ans;  
  105. }  
  106.   
  107. double calculate(string x){  
  108.    x=change(x);  
  109.    string temp;  
  110.    MyStack<double> ans; //为了除法运算方便使用double  
  111.    int len=x.size();  
  112.    for(int i=0;i<len;i++){  
  113.       if(x[i]==‘ ‘)continue;  
  114.       if(x[i]>=‘0‘&&x[i]<=‘9‘){  
  115.          temp="";  
  116.          int j;  
  117.          for(j=i;x[j]>=‘0‘&&x[j]<=‘9‘;j++){  
  118.             temp+=x[j];  
  119.          }  
  120.          i=j-1;  
  121.          ans.push(ToNum(temp));  
  122.       }  
  123.       else{  
  124.          double a=ans.pop(),b=ans.pop();//对于减和乘需要考虑运算顺序所以额外定义两个变量  
  125.          switch(x[i]){  
  126.             case ‘+‘:{ans.push(a+b);break;}  
  127.             case ‘-‘:{ans.push(b-a);break;}  
  128.             case ‘*‘:{ans.push(a*b);break;}  
  129.             case ‘/‘:{ans.push(b/a);break;}  
  130.          }  
  131.       }  
  132.    }  
  133.    return ans.pop();  
  134. }  
  135.   
  136. int main(){  
  137.    string x;  
  138.    cout<<"Please input data."<<endl<<"And don‘t use chinese brackets and don‘t input negative and decimals and space."<<endl;  
  139.    while(cin>>x){  
  140.       cout<<endl<<"answer = "<<calculate(x)<<endl<<endl<<"continue to input or input ctrl+z to break."<<endl;  
  141.    }  
  142. }  

以上是关于逆波兰计算器的主要内容,如果未能解决你的问题,请参考以下文章

9栈-逆波兰计算器(输入为逆波兰表达式)

逆波兰计算器

逆波兰算术表达式 C语言

逆波兰计算器

逆波兰计算器

波兰表达式与逆波兰表达式介绍及中缀表达式转逆波兰表达式代码实现