[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; //存放整数的栈
本人原创,谢谢大家!转载请注明出处,谢谢合作!