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



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

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

再添加小括号的情况。

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

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

 

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


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;
	}//switch
	return num;
}//ch2num
double 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_2
int 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_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;
	}//switch
	return num;
}//ch2num
int 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;
	}//switch
	return num;
}//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);
	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 else
				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) {
						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));
					}//while
					S_ch.push(str[i]);
				}//ifelse
				++i;
			}//if else if else if else
		}//for i
		S_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));
		}//while
		printf("%d\n", S_num.top());
	}//while
	return 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 else
				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) {
						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
		printf("%f\n", S_num.top());
	}//while
	return 0;
}//main

四、剔除空格

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

void replace_space(char*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

放置在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;
	}//calc
public:
	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
};

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

董艳超,第二版,20170224

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值