简单计算器,四则运算,小括号,实数,剔除空格,封装calculator类

来源:互联网 发布:java大数据量并发处理 编辑:程序博客网 时间:2024/06/05 11:57


简单表达式的求值,在《数据结构》教课书上有明确的阐述。

先处理只涉及四则运算的情况。

再添加小括号的情况。

然后处理表达式中包含实数的情况。

最后处理表达式中包含空格的情况。

 

一、对于只涉及加减乘除的表达式.


1设立两个栈,运算符栈和数字栈。

2遍历表达式,解析出里面的数字和运算符。

3数字部分直接压栈,运算符部分视优先级情况而定。

4遍历完毕,数字栈中剩余的那一个数字时,为运算结果。

 

只涉及四则运算的使用,数字全为整数。

 

代码的主要逻辑在main函数中。

ch2num函数完成运算符到数字的映射。

规则为:‘#---0,‘+---1,‘----2,‘*---3,‘/---4

compare二维数组记录运算符之间的优先级。

compare[i][j]=1,表示ij优先级高;compare[i][j]=0,表示i的优先级不高于j

operator_2

函数完成四则运算。简单表达式的求值,在《数据结构》教课书上有明确的阐述。
先处理只涉及四则运算的情况。
再添加小括号的情况。
然后处理表达式中包含实数的情况。
最后处理表达式中包含空格的情况。

对于只涉及加减乘除的表达式,
1设立两个栈,运算符栈和数字栈。
2遍历表达式,解析出里面的数字和运算符。
3数字部分直接压栈,运算符部分视优先级情况而定。
4遍历完毕,数字栈中剩余的那一个数字时,为运算结果。

只涉及四则运算的使用,数字全为整数。

代码的主要逻辑在main函数中。
ch2num函数完成运算符到数字的映射。
规则为:‘#’---0,‘+’---1,‘-’---2,‘*’---3,‘/’---4。
compare二维数组记录运算符之间的优先级。
compare[i][j]=1,表示i比j优先级高;compare[i][j]=0,表示i的优先级不高于j。
operator_2函数完成四则运算。


#include<stdio.h>#include<stack>#include<string.h>using std::stack;int ch2num(char ch) {int num(-1);switch (ch) {case '#':num = 0; break;case '+':num = 1; break;case '-':num = 2; break;case '*':num = 3; break;case '/':num = 4; break;}//switchreturn num;}//ch2numdouble operator_2(double num1, double num2, char ch) {double num(0.0);switch (ch) {case '+':num = num2 + num1; break;case '-':num = num2 - num1; break;case '*':num = num2*num1; break;case '/':num = num2 / num1; break;}//switchreturn num;}//operator_2int compare[5][5] = { { 0 },{ 1 },{ 1 },{ 1,1,1 },{ 1,1,1 } };int main() {freopen("in.txt", "r", stdin);char str[250];stack<double> S_num;stack<char> S_ch;while (gets_s(str)) {while (!S_ch.empty())S_ch.pop();S_ch.push('#');while (!S_num.empty())S_num.pop();int tnum(0);for (int i(0); str[i] != '\0'; ++i) {//累加数字if ('0' <= str[i] && str[i] <= '9') {tnum *= 10;tnum += str[i] - 48;}//遇到运算符,先把数字tnum压入S_num,然后视优先级情况而定下面的操作。else {S_num.push(tnum);tnum = 0;if (compare[ch2num(str[i])][ch2num(S_ch.top())] == 1)S_ch.push(str[i]);//运算符str[i]的优先级较高,直接压入。else {//将S_ch.top()弹出,一直到存在某个S_ch.top()的优先级低于str[i]。//由于S_ch栈底部有个'#',所以不用担心S_ch弹空。while (compare[ch2num(str[i])][ch2num(S_ch.top())] == 0) {char ch = S_ch.top();S_ch.pop();double num1 = S_num.top();S_num.pop();double num2 = S_num.top();S_num.pop();S_num.push(operator_2(num1, num2, ch));}//whileS_ch.push(str[i]);}//if else}//if else}//for iS_num.push(tnum);char ch('\0');//依次计算完所有的运算符while ((ch = S_ch.top()) != '#') {S_ch.pop();double num1 = S_num.top();S_num.pop();double num2 = S_num.top();S_num.pop();S_num.push(operator_2(num1, num2, ch));}//whileprintf("%.2f\n", S_num.top());}//whilereturn 0;}//main 

细节:gets_s函数,gets函数,S_ch栈底预先放置‘#’,作为优先级最低的运算符,功能上类似于“哨兵”。

Freopen(“in.txt”,”r”,stdin)是重定向语句,可以在相应位置安排in.txt文件编辑测试用例,也可以去掉改行代码,自己在控制台输入测试用例。

虽然表达式中只有整数,但是S_num里面存放的元素是double

Compare的维度明显偏大,可以设置成compare[5][3]


二、添加小括号。

逻辑上的主要改变就是‘(’,‘)’括号分开处理。

Str[i]为‘(’,则直接压入S_ch;如果栈顶为‘(’,任何运算符的优先级都比它大。

Str[i]为‘)’,视情况脱去跟它相匹配的那个左括号,参考main里的代码。

优先级部分参考compare[5][6]二维数组。

并且完美支持了正数和负数的处理。

比如:

把这(-2)看作是(0-2)的运算

+2)看作是(0+2)的运算

2)是在有个puts("here")输出那处理的,先从S_numpop出来,稍后再压进去,用这种伎俩来统一流程。

-5+3-5这种式子的,第一个-5是看做0-5来处理的。


#include<stdio.h>#include<stack>using std::stack;int ch2num(const char &ch) {int num(-1);switch (ch) {case'#':num = 0; break;case'+':num = 1; break;case'-':num = 2; break;case'*':num = 3; break;case'/':num = 4; break;case'(':num = 5; break;case')':num = 6; break;}//switchreturn num;}//ch2numint operator_2(const int &num1, const int &num2, const char &ch) {int num(-1);switch (ch) {case'+':num = num2 + num1; break;case'-':num = num2 - num1; break;case'*':num = num2 *num1; break;case'/':num = num2 / num1; break;}//switchreturn num;}//operator_2int compare[5][6] = { { 0 },{ 1, 0, 0,0, 0, 1 },{ 1, 0, 0, 0, 0, 1 },{ 1, 1, 1, 0, 0, 1 },{ 1, 1, 1, 0, 0, 1 } };int main() {freopen("in.txt", "r", stdin);char str[250];stack<int>S_num;stack<char>S_ch;while (gets_s(str)) {while (!S_ch.empty())S_ch.pop();S_ch.push('#');while (!S_num.empty())S_num.pop();int tnum(0);for (int i(0); str[i] != '\0';) {if ('0' <= str[i] && str[i] <= '9') {tnum *= 10;tnum += str[i] - '0';++i;}else if(str[i] == '(') {S_ch.push('(');++i;}else if(str[i] == ')') {S_num.push(tnum);//deal util (char ch = S_ch.top();if (ch != '(') {//just one operator,if this step is ignored,so...S_ch.pop();int num1 = S_num.top();S_num.pop();int num2 = S_num.top();S_num.pop();tnum = operator_2(num1, num2, ch);}else {//puts("here");tnum = S_num.top();S_num.pop();}//if elseS_ch.pop();++i;}else {S_num.push(tnum);tnum = 0;if (compare[ch2num(str[i])][ch2num(S_ch.top())] == 1)S_ch.push(str[i]);else {while (compare[ch2num(str[i])][ch2num(S_ch.top())] == 0) {char ch = S_ch.top();S_ch.pop();int num1 = S_num.top();S_num.pop();int num2 = S_num.top();S_num.pop();S_num.push(operator_2(num1, num2, ch));}//whileS_ch.push(str[i]);}//ifelse++i;}//if else if else if else}//for iS_num.push(tnum);char ch('\0');while ((ch = S_ch.top()) != '#') {S_ch.pop();int num1 = S_num.top();S_num.pop();int num2 = S_num.top();S_num.pop();S_num.push(operator_2(num1, num2, ch));}//whileprintf("%d\n", S_num.top());}//whilereturn 0;}//main


三、添加实数的处理

数字累加的部分发生变化,tnum定义为double型,weight_del定义为小数部分的权重。

int main() {freopen("in.txt", "r", stdin);char str[250];stack<double>S_num;stack<char>S_ch;while (gets_s(str)) {while (!S_ch.empty())S_ch.pop();S_ch.push('#');while (!S_num.empty())S_num.pop();double tnum(0.0);double weight_del(0.0);for (int i(0); str[i] != '\0'; ++i) {if ('0' <= str[i] && str[i] <= '9' || str[i] == '.') {if ('0' <= str[i] && str[i] <= '9') {if (weight_del == 0.0) {tnum *= 10;tnum += str[i] - '0';}else {tnum += weight_del*(str[i] - '0');weight_del *= 0.1;}//if else}else if(str[i] == '.')weight_del = 0.1;}else if(str[i] == '(')S_ch.push('(');else if(str[i] == ')') {S_num.push(tnum);tnum = 0.0;weight_del = 0.0;//deal util (char ch(S_ch.top());if (ch != '(') {//justone operator,if this step is ignored,so...S_ch.pop();double num1 = S_num.top();S_num.pop();double num2 = S_num.top();S_num.pop();tnum = operator_2(num1, num2, ch);}else {//puts("here");tnum = S_num.top();S_num.pop();}//if elseS_ch.pop();//pop(}else {S_num.push(tnum);tnum = 0.0;weight_del = 0.0;if (compare[ch2num(str[i])][ch2num(S_ch.top())] == 1)S_ch.push(str[i]);else {while (compare[ch2num(str[i])][ch2num(S_ch.top())] == 0) {char ch = S_ch.top();S_ch.pop();double num1 = S_num.top();S_num.pop();double num2 = S_num.top();S_num.pop();S_num.push(operator_2(num1, num2, ch));}//whileS_ch.push(str[i]);}//if else}//if else if else if else}//for iS_num.push(tnum);char ch('\0');while ((ch = S_ch.top()) != '#') {S_ch.pop();double num1 = S_num.top();S_num.pop();double num2 = S_num.top();S_num.pop();S_num.push(operator_2(num1, num2, ch));}//whileprintf("%f\n", S_num.top());}//whilereturn 0;}//main

四、剔除空格

如果表达式中含有多余空格的情况,需要预处理一下输入字符串str,就是剔除里面的空格,编写函数如下。

void replace_space(char*str){

   inti(-1), j(-1);

   for(i = 0, j = 0;str[j] !='\0';j++)if (str[j]!=' ')

       str[i++]=str[j];

   str[i]='\0';

   return;

}//replace_space

放置在main函数中的如下位置

while (gets_s(str)){

   replace_space(str);

    。。。

}//while

五、封装calculator类

class Calculator {private:double result;string input;stack<double> S_num;stack<char> S_ch;const int compare[5][6] = { { 0 },{ 1, 0, 0, 0, 0, 1 },{ 1, 0, 0, 0, 0, 1 },{ 1, 1, 1, 0, 0, 1 },{ 1, 1, 1, 0, 0, 1 } };int ch2num(const char &ch) {int num(-1);switch (ch) {case '#':num = 0; break;case '+':num = 1; break;case '-':num = 2; break;case '*':num = 3; break;case '/':num = 4; break;case '(':num = 5; break;case ')':num = 6; break;}//switchreturn num;}//ch2numdouble operator_2(const double &num1, const double &num2, const char &ch) {double num(-1);switch (ch) {case '+':num = num2 + num1; break;case '-':num = num2 - num1; break;case '*':num = num2 * num1; break;case '/':num = num2 / num1; break;}//switchreturn num;}//operator_2void replace_space(string &str) {int i(-1), j(-1);for (i = 0, j = 0; str[j] != '\0'; j++) if (str[j] != ' ')str[i++] = str[j];str[i] = '\0';return;}//replace_spacevoid calc() {string str(input);replace_space(str);if (str == "")return;while (!S_ch.empty())S_ch.pop();S_ch.push('#');while (!S_num.empty())S_num.pop();double tnum(0.0);double weight_del(0.0);for (int i(0); str[i] != '\0'; ++i) {if ('0' <= str[i] && str[i] <= '9' || str[i] == '.') {if ('0' <= str[i] && str[i] <= '9') {if (weight_del == 0.0) {tnum *= 10;tnum += str[i] - '0';}else {tnum += weight_del*(str[i] - '0');weight_del *= 0.1;}//if else}else if (str[i] == '.')weight_del = 0.1;}else if (str[i] == '(')S_ch.push('(');else if (str[i] == ')') {S_num.push(tnum);tnum = 0.0;weight_del = 0.0;char ch(S_ch.top());if (ch != '(') {S_ch.pop();double num1 = S_num.top();S_num.pop();double num2 = S_num.top();S_num.pop();tnum = operator_2(num1, num2, ch);}else {tnum = S_num.top();S_num.pop();}//if elseS_ch.pop();}else {S_num.push(tnum);tnum = 0.0;weight_del = 0.0;if (compare[ch2num(str[i])][ch2num(S_ch.top())] == 1)S_ch.push(str[i]);else {while (compare[ch2num(str[i])][ch2num(S_ch.top())] == 0) {char ch = S_ch.top();S_ch.pop();double num1 = S_num.top();S_num.pop();double num2 = S_num.top();S_num.pop();S_num.push(operator_2(num1, num2, ch));}//whileS_ch.push(str[i]);}//if else}//if else if else if else}//for iS_num.push(tnum);char ch('\0');while ((ch = S_ch.top()) != '#') {S_ch.pop();double num1 = S_num.top();S_num.pop();double num2 = S_num.top();S_num.pop();S_num.push(operator_2(num1, num2, ch));}//whileresult = S_num.top();return;}//calcpublic:Calculator(string input = "") {this->input = input;result = 0.0;return;}//Calculatorvoid inputStr(string input) {this->input = input;result = 0.0;calc();return;}//inputStrdouble getResult() {return result;}//getResult};

本文没有处理非法表达式的部分。

董艳超,第二版,20170224

0 0
原创粉丝点击