计算表达式(数据结构与算法c++版)

问题描述

从键盘上输入中缀表达式,包括括号,计算出表达式的值

  1. 基本要求:

(1)程序能对输入的表达式做简单的判断,如表达式是否有错,能给出适当的提示。

(2)能处理单目运算符:+(正号) -(负号)


一、分析与实现

1.题目分析

(1)先乘方^,再乘除,最后做加减;

(2)同级运算从左算到右;

(3)先括号内,再括号外。

2.算法分析

  1. 初始化两个栈:新建两个栈分别用于储存操作符和操作数
  2. 读取用户输入的表达式,存储在一个string类 str中
  3. 对输入字符串进行简单处理,避免边缘情况发生
  4. 遍历表达式:对str的字符逐个判断
  • 若为(,直接压入操作符栈。
  • 若为数字,创建临时存储字符串,逐步存下数字,将临时字符串转换为double类型压入操作数栈
  • 若为运算符,比较运算符栈顶元素与次运算符的优先级,若栈顶运算符优先级较高,则从操作数栈中获取到两个操作数进行运算,并将结果压入操作数栈中,同时进行相关出栈操作,当栈顶元素优先级小于当前元素时,将当前元素压入运算符栈;
  • 若为),则从操作数栈中获取到两个操作数进行运算,并将结果压入操作数栈中,同时进行相关出栈操作。

二、代码实现

#include<iostream>
#include<string>
#include<stack>
using namespace std;
class MyCalculator {
private:
	//计算器的数据成员
	stack <double>opnd;   //操作数栈
	stack <char>optr;       //操作符栈
	double left;
	double right;

	//辅助函数模板
	int OperPrior(char op);// 操作符优先级
	void Get2Operands(double& left, double& right);//从栈 opnd中退出两个提作数
	double Operate(double left, char op, double right); // 执行运算 left op right
	bool IsOperator(char ch); //判断ch是否为操作符

public:
	//计算器类方法声明
	MyCalculator(); //无参数的构造函数模板
	~MyCalculator(); //析构函数模板
	int Run();//运算表达式
};
MyCalculator::MyCalculator()
{

}


MyCalculator::~MyCalculator()
{

}

int MyCalculator::OperPrior(char op)
{
	int prior = -1;
	switch (op)
	{
	case '+':
	case '-':
		prior = 1;
		break;
	case '*':
	case '/':
	case '%':
		prior = 2;
		break;
	case '^':
		prior = 3;
		break;
	}
	return prior;
}

void MyCalculator::Get2Operands(double& left,double& right)
{
	right = opnd.top();
	opnd.pop();
	left = opnd.top();
	opnd.pop();
}


double MyCalculator::Operate(double left, char op, double right)
{
	if (op == '+')  opnd.push(left + right);
	else if (op == '-')  opnd.push(left - right);
	else if (op == '*')  opnd.push(left * right);
	else if (op == '/')
	{
		if (right == 0.0)
		{
			cout << "表达式有误,除数不能为0";
			return 1;
		}
		opnd.push(left / right);
	}
	else if (op == '%')
	{
		if (right == 0.0)
		{
			cout << "表达式有误,取余的数不能为0";
			return 1;
		}
		if (right != (int)right||left!=(int)left)
		{
			cout << "表达式有误,取余的数不能为小数" << endl;
				return 1;
		}
		opnd.push((int)left % (int)right);
	}
	else if (op == '^')  opnd.push(pow(left, right));
	return 0;
}


bool  MyCalculator::IsOperator(char ch)
{
	switch (ch)
	{
	case '+':
	case '-':
	case '*':
	case '/':
	case '%':
	case '^':
	case '.':
		return true;
	}
	return false;
}

int  MyCalculator::Run()
{
	string str; 
	string ss;
	char priorChar;              
	double operand;            //操作数
	char op;                     //操作符
	cout << "输入表达式:" << endl;
	cin >> str;
	str.erase(str.length()-1,1);
	str = '(' + str + ')';
	for (int i = 0; i < str.length(); i++)
	{
		if (str[i] == '(')  optr.push(i);
		else if (str[i] == ')')
		{

			if (optr.empty())
			{
				cout << "表达式有误,括号不匹配";
				return 1;
			}
			optr.pop();
		}
		else if (!((str[i] >= '0' && str[i] <= '9') || IsOperator(str[i]) ))
		{
			cout << "表达式有误,存在不支持的运算符";
			return 1;
		}
	}
	if (!optr.empty())
	{
		cout << "表达式有误,括号不匹配";
		return 1;
	}

	for (int i = 0; i < str.length(); i++)
	{
		if (str[i] == '(' && str[i + 1] == '-')  str.insert(i + 1, "0");
		if (str[i] == '(' && str[i + 1] == '+')  str.insert(i + 1, "0");
	}
	for (int i = 0; i < str.length(); i++)
	{
		if (str[i] == '(')
			optr.push(str[i]);
		else if ((str[i] <= '9' && str[i] >= '0'))
		{
			
			ss += str[i];
			if (str[i + 1] == '.') { ss += '.'; i++; }
			else if (!(str[i + 1] <= '9' && str[i + 1] >= '0'))
			{
				operand = stof(ss);
				opnd.push(operand);
				ss = "";
			}
		}
		else if (OperPrior(str[i]) > 0)
		{
			if (OperPrior(str[i + 1]) > 0)
			{
				cout << "表达式有误" << endl;
				return 1;
			}
			while (OperPrior(optr.top()) >= OperPrior(str[i]))
			{
				Get2Operands(left, right);
				op = optr.top(); optr.pop();
				if(Operate(left, op, right))
					return 1;
			}
			optr.push(str[i]);
			
		}
		else 
		{
			while (optr.top() != '(')
			{
				Get2Operands(left, right);
				op = optr.top(); optr.pop();
				if(Operate(left,  op, right))
					return 1;
			}
			optr.pop();
		}
	}
	cout << "计算结果为" << opnd.top() << endl;
	return 0;
}

int main()
{
	MyCalculator m;
	char ans = 'y';
	while (ans == 'y')
	{
		if(m.Run())
			return 0;
		cout << "是否继续(y/n)?";
		cin >> ans;
	}
	return 0;
}
	

运行截图:

程序有待进一步测试与改进。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值