[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;                       //存放整数的栈

 

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

posted @ 2016-10-22 14:36  Alexios_Yan  阅读(1770)  评论(0编辑  收藏  举报