zoukankan      html  css  js  c++  java
  • [C++]实现10以内整数的简单科学计算器

          大家好!今天带来的是自己实现的用C++实现的10以内整数的科学计算器,其中涉及中缀表达式后缀表达式(逆波兰表示法),后缀表达式的求值,涉及栈这一数据结构的压栈,弹栈,存取栈顶元素和判断栈是否为空等操作.

         计算器在生活中应用广泛.众所周知,我们往计算器中输入的是由数字,运算符组成的表达式,这个表达式被称为中缀表达式,因其运算符写在数的中间,如(1+2)*3.而用栈实现的计算器所处理的是后缀表达式,即运算符在数字的后面,这涉及到中缀表达式转后缀表达式的算法.如(1+2)*3的后缀表达式是12+3*.后缀表达式也称为逆波兰表示法,因其是一种由波兰数学家扬·武卡谢维奇在1920年引入的数学表达式方式.

        整个工程涉及两个编译单元,即main.cpp主函数文件和caculatefuncs.h自定义头文件.main.cpp的代码十分简单,就是读入中缀表达式,然后调用toPostFix函数,转变为后缀表达式,再调用toDouble函数将后缀表达式求值.代码如下:

     1 #include <iostream>
     2 #include"caculatefuncs.h"
     3 
     4 using namespace std;
     5 
     6 int main()
     7 {
     8 
     9     string infix;
    10 
    11     cout << "输入中缀表达式:" << endl;
    12     cin >> infix;
    13 
    14     string postfix = toPostFix(infix);
    15     cout << "对应的后缀表达式(逆波兰表示法)为" << postfix << endl;
    16     cout << "表达式的值为:" << toDouble(postfix) << endl;
    17     return 0;
    18 }

    caculatefuncs.h中包含两个函数toPostFix和toDouble的实现.中缀转后缀的算法有一点复杂,规则如下:

    toPostFix函数的实现:

      1 string toPostFix(const string &infix)           //中缀表达式转后缀表达式函数
      2 {
      3 
      4     const int n = infix.length();
      5     const char PRI1 = '2';
      6     const char PRI2 = '1';              //优先级定义
      7     const char UN = '0';
      8     string postfix( n, ' ');                //预留后缀表达式字符串
      9     string priority( n, ' ');               //预留优先级字符串
     10     int i = 0;                                 // infix序数
     11     int j = 0;                                 //priority序数
     12     int k = 0;                                //postfix序数
     13 
     14     for ( ; i < n; i++)
     15     {
     16         if (infix.at(i) >= '0' && infix.at(i) <= '9')
     17             postfix.at(k++) = infix.at(i);            //数字直接存入
     18 
     19         else
     20         {
     21 
     22             switch (infix.at(i))
     23             {
     24                 case '+':
     25                     priority.at(j++) = PRI2;
     26                     break;
     27 
     28                 case '-':
     29                     priority.at(j++) = PRI2;
     30                     break;
     31 
     32                 case '*':
     33                     priority.at(j++) = PRI1;
     34                     break;
     35 
     36                 case '/':
     37                     priority.at(j++) = PRI1;
     38                     break;
     39 
     40                 case '(':
     41                     priority.at(j++) = UN;
     42                     break;
     43 
     44                 case ')':
     45                     while (charStack.top() != '(')
     46                     {
     47                         postfix.at(k++) = charStack.top();
     48                         charStack.pop();
     49                         j--;
     50                     }
     51 
     52                     charStack.pop();
     53                     j--;
     54                     break;
     55 
     56                 default:
     57                     try
     58                     {
     59                         throw runtime_error("unknown operator");
     60                     }
     61                     catch (runtime_error err)
     62                     {
     63                         cout << err.what();
     64                         exit(EXIT_FAILURE);
     65                     }                                  //优先级字符串中存放代表优先级的字符常量
     66             }
     67 
     68             if ( j > 1 && priority.at(j - 1) < priority.at(j - 2) && priority.at(j - 1) != UN && priority.at(j - 2) != UN) //当前运算符优先级比栈顶运算符低,则待高优先级运算符弹栈后入栈
     69             {
     70                 postfix.at(k++) = charStack.top();
     71                 charStack.pop();
     72                 charStack.push(infix.at(i));
     73                 priority.at(j - 2) = priority.at(j - 1);
     74                 j--;
     75             }
     76             else  if ( infix.at(i) != ')')
     77                 charStack.push(infix.at(i));
     78 
     79             if ( j > 1)
     80             {
     81                 for ( int m = j - 2; (m >= 0) && (priority.at(m) > priority.at(j - 1)); m--) //优先级比较,高于当前运算符优先级的弹栈
     82                 {
     83                     if (priority.at(m) != UN && priority.at(j - 1) != UN )
     84                     {
     85                         postfix.at(k++) = charStack.top();
     86                         charStack.pop();
     87                         j--;
     88                     }
     89                 }
     90             }
     91         }
     92     }
     93 
     94     while ( !charStack.empty())                           //栈中字符全部弹出
     95     {
     96         postfix.at(k++) = charStack.top();
     97         charStack.pop();
     98     }
     99 
    100     postfix = postfix.substr(0, k);
    101     return postfix;
    102 }

    至于后缀表达式求值的算法,我们都比较熟悉了.遍历后缀表达式,若是操作数,则压入栈;若为运算符,则从栈中弹出两个操作数,进行计算,然后将计算结果压栈.直至遍历完成时,栈为空.

    toDouble函数的实现:

     1 double toDouble(const string &postfix)                         //逆波兰表示法转换为整数函数
     2 {
     3 
     4     const int n = postfix.length();
     5     double a = 0;              //第一个操作数
     6     double b = 0;             //第二个操作数
     7 
     8     for (int i = 0; i < n; i++)
     9     {
    10         char temp = postfix.at(i);
    11 
    12         if (temp >= '0' && temp <= '9') //是数字则压栈
    13             doubleStack.push( temp - '0');
    14         else                                            //运算符分情况讨论
    15         {
    16             switch (temp)
    17             {
    18                 case '+':
    19                     b = doubleStack.top();
    20                     doubleStack.pop();
    21                     a = doubleStack.top();
    22                     doubleStack.pop();
    23                     doubleStack.push(a + b);       //运算结果压栈
    24                     break;
    25 
    26                 case '-':
    27                     b = doubleStack.top();
    28                     doubleStack.pop();
    29                     a = doubleStack.top();
    30                     doubleStack.pop();
    31                     doubleStack.push(a - b);
    32                     break;
    33 
    34                 case '*':
    35                     b = doubleStack.top();
    36                     doubleStack.pop();
    37                     a = doubleStack.top();
    38                     doubleStack.pop();
    39                     doubleStack.push(a * b);
    40                     break;
    41 
    42                 case '/':
    43                     try
    44                     {
    45                         b = doubleStack.top();
    46 
    47                         if (b == 0)
    48                         {
    49                             throw runtime_error("divided 0");
    50                         }
    51                     }
    52                     catch (runtime_error err)
    53                     {
    54                         cout << err.what() << endl;
    55                         exit(EXIT_FAILURE);
    56                     }
    57 
    58                     doubleStack.pop();
    59                     a = doubleStack.top();
    60                     doubleStack.pop();
    61                     doubleStack.push(a / b);
    62                     break;
    63 
    64                 default:
    65                     try
    66                     {
    67                         throw runtime_error("unknown operator");
    68                     }
    69                     catch (runtime_error err)
    70                     {
    71                         cout << err.what();
    72                         exit(EXIT_FAILURE);
    73                     }
    74             }
    75         }
    76     }
    77 
    78     return doubleStack.top();  //最终结果弹栈
    79 }

    这个简单计算器实现只能处理10以内的整数,但结果可以为浮点数.可以处理括号,考虑运算符优先级.栈的是运用了C++的模板类Stack,类声明被包含在头文件stack中.本程序使用的两个栈定义如下:

    stack<char> charStack;                  //存放字符的栈
    stack<double> doubleStack;                       //存放整数的栈

    本人原创,谢谢大家!转载请注明出处,谢谢合作!

  • 相关阅读:
    nth-child与nth-of-type
    改变事件绑定的this的问题
    瀑布流的一些CSS实现方式
    事件捕获与冒泡的再探
    为学
    ECharts导出word 图表模糊失真
    垂直对齐:vertical-align:super属性
    Vuex- Action的 { commit } {commit}是什么写法
    修改对象中的属性名
    echarts 角度渐变环形图心得
  • 原文地址:https://www.cnblogs.com/Agent-YRBlogs/p/5987603.html
Copyright © 2011-2022 走看看