四则运算实现

简单版(无括号)

Sample Input:

1 + 1 / 1 * 1 - 1

Sample Output:

1.00

步骤

  1. 由输入的运算时字符串提取数字与运算符,从而得到中缀表达式
  2. 由中缀表达式转换为后缀表达式
  3. 通过stack来计算后缀表达式

参考代码

#include <iostream>
#include <algorithm>
#include <string>
#include <stack>
#include <vector>
#include <map>
#include <cmath>
using namespace std;
map<string, int> m;		//运算符优先级

bool judgeNum(string str)	//判断是不是数字
{
	if(str[0] >= '0' && str[0] <= '9')
		return true;
	return false;
}

void GetMid(const string str, vector<string> &v) 			//由输入的字符串提取中缀表达式
{
	string s0;
	for (int i = 0; i < str.size(); i++)
	{
		if (str[i] == ' ')
			continue;
		s0.clear();
		if (str[i] == '+' || str[i] == '-' || str[i] == '*' || str[i] == '/')
		{
			s0 += str[i], v.push_back(s0);
			continue;
		}

		bool tag = false;
		while (str[i] >= '0' && str[i] <= '9')
			s0 += str[i], tag = true, i++;
		if (tag)
			v.push_back(s0), i--;
	}
}

void GetBack(const vector<string> v, vector<string> &vb)		//由中缀表达式Get后缀表达式(简易版, 不带括号)
{
	stack<string> s;
	for (int i = 0; i < v.size(); i++)
	{
		/*遇到数字直接加入后缀序列*/
		if (judgeNum(v[i]))
		{
			vb.push_back(v[i]);
			continue;
		}

		/*遇到运算符, 进一步判断*/
		if (s.empty() || m[v[i]] < m[s.top()])
			s.push(v[i]);
		else{
			while (!s.empty() && m[v[i]] >= m[s.top()])
				vb.push_back(s.top()), s.pop();
			s.push(v[i]);
		}
	}
	/*栈中剩余运算符的直接加入后缀表达式*/
	while (!s.empty())
		vb.push_back(s.top()), s.pop();
}

bool Calculate(const vector<string> vb, double &ans)			//计算后缀表达式
{
	stack<double> s;
	for (int i = 0; i < vb.size(); i++)
		if(judgeNum(vb[i]))		//如果是数字
			s.push(stod(vb[i]));
		else{
			double a, b;
			b = s.top(), s.pop();
			a = s.top(), s.pop();
			if(vb[i] == "+")
				a += b;
			else if(vb[i] == "-")
				a -= b;
			else if(vb[i] == "*")
				a *= b;
			else{
				if(abs(b) <= 1e-6)
					return false;
				a /= b;
			}
			s.push(a);
		}
	//cout << s.size() << endl;
	ans = s.top();
	return true;
}

int main()
{
	double ans;
	string str;
	vector<string> v, vb; //中缀表达式与后缀表达式
	getline(cin, str);
	/*初始化表示运算符的优先级*/
	m["+"] = m["-"] = 2;
	m["*"] = m["/"] = 1;

	GetMid(str, v);
	GetBack(v, vb);
	if (!Calculate(vb, ans))
		cout << "Cannot be divided by 0" << endl;
	else
		printf("%.2f\n", ans);

	system("pause");
	return 0;
}
/*
2+1-2*3-4+5
*/

标准版(有括号)

编写程序,从键盘输入一个合法的表达式,对该表达式进行求值并输出,为降低题目难度,特做如下要求:

运算数均为整型数(即不带小数点)
运算符只支持加减乘除四种(+、-、*、/)以及小括号(())
计算规则为实型数运算规则,例如1/2=0.5
输出计算结果保留两位小数(四舍五入)
表达式中不允许出现如下情况

  1. 空字符串
  2. 错误的运算符
  3. 错误的运算数
  4. 括号不匹配
  5. 空括号
  6. 连续的运算符,例如–5
  7. 运算符为正数时,其符号+必须省略,例如+2+4定义为非法,而负数时为合法,例如-2+4
  8. 程序要能处理表达式中间出现的空格(输入表达式中存在空格为合法情况)
  9. 其他不符合表达式书写规则的情况

输入格式:

从键盘输入一行表达式。例如2+3*(5 -6 / 4)/3 +26-300*3/29

输出格式:

有以下三种输出结果:

表达式不合法时,输出Wrong Format
出现无法计算情况时(例如除0),输出输入表达式 = NaN
能够正确运算时,输出输入表达式 = 计算结果

输入样例1:

在这里给出一组输入。例如:

2+3*(5  -6   /    4)/3 +26-300*3/29

输出样例1:

在这里给出相应的输出。例如:

2+3*(5  -6   /    4)/3 +26-300*3/29 = 0.47

输入样例2:

在这里给出一组输入。例如:

2+3-      5  /   0       

输出样例2:

在这里给出相应的输出。例如:

2+3-      5  /   0         = NaN

输入样例3:

在这里给出一组输入。例如:

((2-3/4*5/4  +8-0.4)/100-003*5

输出样例3:

在这里给出相应的输出。例如:

Wrong Format

解题思路

(摘自下文参考博客)
在这里插入图片描述
代码:

#include <iostream>					//表达式求值(带括号)
#include <algorithm>
#include <string>
#include <vector>
#include <map>
#include <stack>
#include <cmath>
using namespace std;

bool GetMid(string str, vector<string> &vm)							//得到中缀表达式, 返回判断表达式是否合法
{
	string s0;
	stack<string> s;
	for (int i = 0; i < str.size(); i++)
	{
		bool tag = false;
		while (str[i] >= '0' && str[i] <= '9' && i < str.size())	//如果是数字
			tag = true, s0 += str[i++];
		if(tag)
			vm.push_back(s0), s0.clear(), i--;
		if(str[i] != ' ' && !tag)									//如果是操作符
		{
			s0 += str[i];
			vm.push_back(s0);
			s0.clear();
		}
	}
	int cnt = 0;
	for (int i = 0; i < vm.size(); i++)
	{
		if(vm[i] == "(" || vm[i] == ")")
		{
			if(vm[i] == "(")
				s.push(vm[i]);
			else{
				if(s.empty() || s.top() == ")")
					return false;
				if(s.top() == "(")
					s.pop();
			}
			continue;
		}
		cnt++;
		//cout << cnt << " " << vm[i] << endl;
		if (!(cnt % 2) && vm[i][0] >= '0' && vm[i][0] <= '9' || cnt % 2 && !(vm[i][0] >= '0' && vm[i][0] <= '9'))
			return false;
	}
	if(!s.empty())
		return false;
	// for (int i = 0; i < vm.size(); i++)
	// 	cout << vm[i] << " ";
	// cout << endl;
	return true;
}

void Mid_to_back(const vector<string> vm, vector<string> &vb)		//中缀表达式得后缀表达式
{
	stack<string> s;
	map<string, int> m;	//运算符优先级
	m["*"] = m["/"] = 1;
	m["+"] = m["-"] = 2;

	for (int i = 0; i < vm.size(); i++)
		if(vm[i][0] >= '0' && vm[i][0] <= '9')		//如果是数字直接输出
			vb.push_back(vm[i]);
		else{
			if(vm[i] == "(")
				s.push(vm[i]);
			else if(vm[i] == ")")
			{
			//	cout << ")" << endl;
				while (!s.empty() && s.top() != "(")
				{
					//cout << s.top() << endl;
					vb.push_back(s.top());			//输出
					s.pop();
				}
				//cout << s.top() << endl;
				if(!s.empty() && s.top() == "(")
					s.pop();
			}
			else{
				if(s.empty() || m[vm[i]] < m[s.top()] || s.top() == "(")
					s.push(vm[i]);
				else{
					while (!s.empty() && m[vm[i]] >= m[s.top()] && s.top() != "(") //
						vb.push_back(s.top()), s.pop();
					s.push(vm[i]);
				}
			}
		}
	while (!s.empty())
		vb.push_back(s.top()), s.pop();

	// for (int i = 0; i < vb.size(); i++)
	// 	cout << vb[i] << " ";
	// cout << endl;
}

bool Calculate_back(vector<string> vb, double &ans)					//运用stack计算后缀表达式
{
	stack<double> s;
	double t;
	for (int i = 0; i < vb.size(); i++)
		if(vb[i][0] >= '0' && vb[i][0] <= '9')	//入栈
			s.push(stod(vb[i]));
		else{
			double a, b;
			b = s.top(), s.pop();
			a = s.top(), s.pop();
			if (vb[i] == "+")
				a += b;
			else if (vb[i] == "-")
				a -= b;
			else if (vb[i] == "*")
				a *= b;
			else{
				if (abs(b) <= 1e-6)
					return false;
				a /= b;
			}
			s.push(a);
		}
	if(!s.empty())
		ans = s.top();
	return true;
}


int main()
{
	string str;
	double ans;
	vector<string> vm, vb;		//用于提取字符串所表示的中缀表达式, 及转换的后缀表达式
	getline(cin, str);
	if(GetMid(str, vm))
	{
		Mid_to_back(vm, vb);
		cout << str << " = ";
		if(Calculate_back(vb, ans))
			printf("%.2f\n", ans);
		else
			cout << "NaN";
	}
	else
		cout << "Wrong Format" << endl;

	system("pause");
	return 0;
}
/*
1)如果遇到操作数,我们就直接将其输出。

2)如果遇到操作符,则我们将其放入到栈中,遇到左括号时我们也将其放入栈中。

3)如果遇到一个右括号,则将栈元素弹出,将弹出的操作符输出直到遇到左括号为止。注意,左括号只弹出并不输出。

4)如果遇到任何其他的操作符,如(“+”, “*”,“(”)等,从栈中弹出元素直到遇到发现更低优先级的元素(或者栈为空)为止。弹出完这些元素后,才将遇到的操作符压入到栈中。有一点需要注意,只有在遇到" ) "的情况下我们才弹出" ( ",其他情况我们都不会弹出" ( "。

5)如果我们读到了输入的末尾,则将栈中所有元素依次弹出。
*/

参考博客:
https://blog.csdn.net/ssjhust123/article/details/8001651

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值