首页 > 学院 > 开发设计 > 正文

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

2019-11-08 02:43:49
字体:
来源:转载
供稿:网友


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

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

再添加小括号的情况。

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

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

 

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

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

函数完成四则运算。简单表达式的求值,在《数据结构》教课书上有明确的阐述。先处理只涉及四则运算的情况。再添加小括号的情况。然后处理表达式中包含实数的情况。最后处理表达式中包含空格的情况。对于只涉及加减乘除的表达式,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;	}//switch	return 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;	}//switch	return 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));					}//while					S_ch.push(str[i]);				}//if else			}//if else		}//for i		S_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));		}//while		PRintf("%.2f/n", S_num.top());	}//while	return 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_num里pop出来,稍后再压进去,用这种伎俩来统一流程。

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

#include<stdio.h>

#include<stack>

using std::stack;

 

int ch2num(constchar&ch) {

   intnum(-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;

   }//switch

   returnnum;

}//ch2num

int operator_2(constint&num1,constint&num2,constchar&ch) {

   intnum(-1);

   switch(ch){

   case'+':num = num2 +num1;break;

   case'-':num = num2 -num1;break;

   case'*':num = num2 *num1;break;

   case'/':num = num2 /num1;break;

   }//switch

   returnnum;

}//operator_2

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 main() {

   freopen("in.txt","r",stdin);

   charstr[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();

       inttnum(0);

       for(inti(0); str[i] != '/0';) {

           if('0' <= str[i] && str[i] <= '9') {

               tnum*= 10;

               tnum+= str[i] - '0';

               ++i;

           }

           elseif(str[i] == '(') {

               S_ch.push('(');

               ++i;

           }

           elseif(str[i] == ')') {

               S_num.push(tnum);

               //dealutil (

               charch = S_ch.top();

               if(ch !='(') {//justone operator,if this step is ignored,so...

                   S_ch.pop();

                   intnum1 = S_num.top();

                   S_num.pop();

                   intnum2 = S_num.top();

                   S_num.pop();

                   tnum= operator_2(num1, num2, ch);

               }

               else{

                   //puts("here");

                   tnum= S_num.top();

                   S_num.pop();

               }//ifelse

               S_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) {

                       charch = S_ch.top();

                       S_ch.pop();

                       intnum1 = S_num.top();

                       S_num.pop();

                       intnum2 = S_num.top();

                       S_num.pop();

                       S_num.push(operator_2(num1,num2, ch));

                   }//while

                   S_ch.push(str[i]);

               }//ifelse

               ++i;

           }//ifelse if else if else

       }//fori

       S_num.push(tnum);

       charch('/0');

       while((ch = S_ch.top()) !='#') {

           S_ch.pop();

           intnum1 = S_num.top();

           S_num.pop();

           intnum2 = S_num.top();

           S_num.pop();

           S_num.push(operator_2(num1,num2, ch));

       }//while

       printf("%d/n", S_num.top());

   }//while

   return0;

}//main

三、添加实数的处理

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

int main() {

   freopen("in.txt","r",stdin);

   charstr[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();

       doubletnum(0.0);

       doubleweight_del(0.0);

       for(inti(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;

                   }//ifelse

               }

               elseif(str[i] == '.')weight_del = 0.1;

           }

           elseif(str[i] == '(')S_ch.push('(');

           elseif(str[i] == ')') {

               S_num.push(tnum);

               tnum= 0.0;

               weight_del= 0.0;

               //dealutil (

               charch(S_ch.top());

                if(ch != '(') {//justone operator,if this step is ignored,so...

                   S_ch.pop();

                   doublenum1 = S_num.top();

                   S_num.pop();

                   doublenum2 = S_num.top();

                   S_num.pop();

                   tnum= operator_2(num1, num2, ch);

               }

               else{

                   //puts("here");

                   tnum= S_num.top();

                   S_num.pop();

               }//ifelse

               S_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) {

                       charch = S_ch.top();

                       S_ch.pop();

                       doublenum1 = S_num.top();

                       S_num.pop();

                       doublenum2 = S_num.top();

                       S_num.pop();

                       S_num.push(operator_2(num1,num2, ch));

                   }//while

                   S_ch.push(str[i]);

               }//ifelse

           }//ifelse if else if else

       }//fori

        S_num.push(tnum);

       charch('/0');

       while ((ch =S_ch.top()) !='#') {

           S_ch.pop();

           doublenum1 = S_num.top();

           S_num.pop();

           doublenum2 = S_num.top();

           S_num.pop();

           S_num.push(operator_2(num1,num2, ch));

       }//while

       printf("%f/n", S_num.top());

   }//while

   return0;

}//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;		}//switch		return num;	}//ch2num	double 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;		}//switch		return num;	}//operator_2	void 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_space	void 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 else				S_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));					}//while					S_ch.push(str[i]);				}//if else			}//if else if else if else		}//for i		S_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));		}//while		result = S_num.top();		return;	}//calcpublic:	Calculator(string input = "") {		this->input = input;		result = 0.0;		return;	}//Calculator	void inputStr(string input) {		this->input = input;		result = 0.0;		calc();		return;	}//inputStr	double getResult() {		return result;	}//getResult};

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


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表