数学表达式解析器实现(Evaluate mathematical expression)

Instructions Given a mathematical expression as a string you must
return the result as a number.

Numbers Number may be both whole numbers and/or decimal numbers. The
same goes for the returned result.

Operators You need to support the following mathematical operators:

Multiplication * Division / (as true division) Addition + Subtraction

  • Operators are always evaluated from left-to-right, and * and / must be evaluated before + and -.

Parentheses You need to support multiple levels of nested parentheses,
ex. (2 / (2 + 3.33) * 4) - -6

Whitespace There may or may not be whitespace between numbers and
operators.

An addition to this rule is that the minus sign (-) used for negating
numbers and parentheses will never be separated by whitespace. I.e.,
all of the following are valid expressions.

1-1 // 0 1 -1 // 0 1- 1 // 0 1 - 1 // 0 1- -1 // 2 1 - -1 //
2

6 + -(4) // 2 6 + -( -4) // 10 And the following are invalid
expressions

1 - - 1 // Invalid 1- - 1 // Invalid 6 + - (4) // Invalid 6 +
-(- 4) // Invalid

解题:
 输入一个数学表达式字符串,支持’+’,’-’,’*’,’/’,以及’(’,’)’,并且支持’负数
思路:
 先将字符串转化为逆波兰表达式,之后再对逆波兰表达式进行求值,在处理负数时,先将负数改为@。
程序:
中缀表达式转换为逆波兰表达式:

  bool to_postfix(const std::string& expression, std::vector<CTokener>&outResults)
    {
    	int Len = expression.size();
    	std::string strNum;
    	std::stack<char> operatorstack;
    	for (int i = 0; i < Len; i++)
    	{
    		char ch = expression[i];
    		if (isNum(ch))
    		{
    			strNum.push_back(ch);
    		}
    		else
    		{
    			if (!strNum.empty())
    			{
    				CTokener token;
    				token.m_value = strNum;
    				token.m_tokenType = CTokener::eNum;
    				outResults.push_back(token);
    				strNum.clear();
    			}
    			if (ch==' ')
    			{
    				continue;
    			}
    			if (ch == '-')
    			{
    				char chnext = expression[i + 1];
    				if (chnext == '(' || isNum(chnext))
    				{
    					char prev = findleftoperaotr(expression, i);
    					if (isSymbol(prev) ||prev==' '||prev=='(')
    					{
    						operatorstack.push('@');
    						continue;
    					}
    				}
    			}
    			if (operatorstack.empty() ||ch=='(')
    			{
    				operatorstack.push(ch);
    			}
    			else if (ch ==')')
    			{
    				char chtop = operatorstack.top();
    				while (chtop != '(')
    				{
    					std::string strTemp(1,chtop);
    					CTokener token;
    					token.m_value = strTemp;
    					token.m_tokenType =(CTokener::TokenType)(TokenTypeMap[chtop]);
    					outResults.push_back(token);
    					operatorstack.pop();
    					chtop = operatorstack.top();
    				}
    				if (chtop == '(')
    				{
    					operatorstack.pop();
    				}
    			}
    			else
    			{
    				char chtop = operatorstack.top();
    				if (comparePriority(ch, chtop))
    				{
    					operatorstack.push(ch);
    				}
    				else
    				{
    					while (!comparePriority(ch, chtop) && !operatorstack.empty())
    					{
    						std::string strTemp(1, chtop);
    						CTokener token;
    						token.m_value = strTemp;
    						token.m_tokenType = (CTokener::TokenType)(TokenTypeMap[chtop]);
    						outResults.push_back(token);
    						operatorstack.pop();
    						if (operatorstack.size())
    						{
    							chtop = operatorstack.top();
    						}
    					}
    					operatorstack.push(ch);
    				}
    			}
    		}
    	}
    	if (!strNum.empty())
    	{
    		CTokener token;
    		token.m_value = strNum;
    		token.m_tokenType = CTokener::eNum;
    		outResults.push_back(token);
    		strNum.clear();
    	}
    
    	while (!operatorstack.empty())
    	{
    		char chtop = operatorstack.top();
    		std::string strTemp(1, chtop);
    		CTokener token;
    		token.m_value = strTemp;
    		token.m_tokenType = (CTokener::TokenType)(TokenTypeMap[chtop]);
    		outResults.push_back(token);
    		operatorstack.pop();
    	}
    	return true;
    }

完整源码如下:

	#include <string>
#include <vector>
#include <algorithm>
#include <map>
#include <stack>

class CTokener
{
public:
	enum TokenType
	{
		eNum =1, //值
		eSymbolStart,
		eLeftBrakets, //(
		eRightBrakets, //)
		eAdd,//+
		eSub,//-
		eMul,//*
		eDevide,// /
		eSymbolEnd,
		eNeg,
	};

public:
	TokenType m_tokenType;
	std::string m_value;
};
std::map<char, int> TokenTypeMap =
{
	{ '(',CTokener::eLeftBrakets },
	{ ')',CTokener::eRightBrakets },
	{ '+',CTokener::eAdd },
	{ '-',CTokener::eSub },
	{ '*',CTokener::eMul },
	{ '/',CTokener::eDevide },
	{ '@',CTokener::eNeg },
};

bool isNum(const char &ch)
{
	if (ch >='0' &&ch <='9' ||ch=='.')
	{
		return true;
	}
	return false;
}
const std::string strSymbol = "+-*/";
bool isSymbol(const char &ch)
{
	if (strSymbol.find(ch) != std::string::npos)
	{
		return true;
	}
	return false;
}
bool checkleftIsOperaotr(const std::string& expression, int iCurIndex)
{
	for (int i=iCurIndex-1;i >=0;i--)
	{
		char chcur = expression[i];
		if (chcur ==' ')
		{
			continue;
		}
		if (isSymbol(chcur) ||chcur =='(')
		{
			return false;
		}
		return true;
	}
	return false;
}
char findleftoperaotr(const std::string& expression, int iCurIndex)
{
	for (int i = iCurIndex - 1; i >= 0; i--)
	{
		char chcur = expression[i];
		if (chcur == ' ')
		{
			continue;
		}
		return chcur;
	}
	return ' ';
}
bool comparePriority(char ch1, char ch2)
{
	if (ch2 == '(')
	{
		return true;
	}
	if (ch1 =='@')
	{
		return true;
	}
	if (ch1 == '*' || ch1 == '/')
	{
		if (ch2 == '+' || ch2 == '-')
		{
			return true;
		}
	}
	return false;
}
bool to_postfix(const std::string& expression, std::vector<CTokener>&outResults)
{
	int Len = expression.size();
	std::string strNum;
	std::stack<char> operatorstack;
	for (int i = 0; i < Len; i++)
	{
		char ch = expression[i];
		if (isNum(ch))
		{
			strNum.push_back(ch);
		}
		else
		{
			if (!strNum.empty())
			{
				CTokener token;
				token.m_value = strNum;
				token.m_tokenType = CTokener::eNum;
				outResults.push_back(token);
				strNum.clear();
			}
			if (ch==' ')
			{
				continue;
			}
			if (ch == '-')
			{
				char chnext = expression[i + 1];
				if (chnext == '(' || isNum(chnext))
				{
					char prev = findleftoperaotr(expression, i);
					if (isSymbol(prev) ||prev==' '||prev=='(')
					{
						operatorstack.push('@');
						continue;
					}
				}
			}
			if (operatorstack.empty() ||ch=='(')
			{
				operatorstack.push(ch);
			}
			else if (ch ==')')
			{
				char chtop = operatorstack.top();
				while (chtop != '(')
				{
					std::string strTemp(1,chtop);
					CTokener token;
					token.m_value = strTemp;
					token.m_tokenType =(CTokener::TokenType)(TokenTypeMap[chtop]);
					outResults.push_back(token);
					operatorstack.pop();
					chtop = operatorstack.top();
				}
				if (chtop == '(')
				{
					operatorstack.pop();
				}
			}
			else
			{
				char chtop = operatorstack.top();
				if (comparePriority(ch, chtop))
				{
					operatorstack.push(ch);
				}
				else
				{
					while (!comparePriority(ch, chtop) && !operatorstack.empty())
					{
						std::string strTemp(1, chtop);
						CTokener token;
						token.m_value = strTemp;
						token.m_tokenType = (CTokener::TokenType)(TokenTypeMap[chtop]);
						outResults.push_back(token);
						operatorstack.pop();
						if (operatorstack.size())
						{
							chtop = operatorstack.top();
						}
					}
					operatorstack.push(ch);
				}
			}
		}
	}
	if (!strNum.empty())
	{
		CTokener token;
		token.m_value = strNum;
		token.m_tokenType = CTokener::eNum;
		outResults.push_back(token);
		strNum.clear();
	}

	while (!operatorstack.empty())
	{
		char chtop = operatorstack.top();
		std::string strTemp(1, chtop);
		CTokener token;
		token.m_value = strTemp;
		token.m_tokenType = (CTokener::TokenType)(TokenTypeMap[chtop]);
		outResults.push_back(token);
		operatorstack.pop();
	}
	return true;
}
double calc(std::string expression) {

	int Len = expression.size();
	if (Len <=0)
	{
		return 0;
	}
	std::vector<CTokener>postfix;
	if (!to_postfix(expression,postfix))
	{
		return 0;
	}
	std::stack<double> results;
	for (int i=0;i <postfix.size();i++)
	{
		const CTokener &tempToken = postfix[i];
		switch (tempToken.m_tokenType)
		{
		case  CTokener::eNum:
		{
			double value = std::stod(tempToken.m_value);
			results.push(value);
		}
		break;
		case CTokener::eNeg:
		{
			double value1 = results.top();
			results.pop();
			double dtemp = value1 *-1.0;
			results.push(dtemp);
		}
		break;
		case CTokener::eAdd:
		{
			double value1 = results.top();
			results.pop();
			double value2 = results.top();
			results.pop();
			double dtemp = value1 + value2;
			results.push(dtemp);
		}
		break;
		case CTokener::eSub:
		{
			double value1 = results.top();
			results.pop();
			double value2 = results.top();
			results.pop();
			double dtemp = value2 - value1;
			results.push(dtemp);
		}
		break;
		case CTokener::eMul:
		{
			double value1 = results.top();
			results.pop();
			double value2 = results.top();
			results.pop();
			double dtemp = value2 * value1;
			results.push(dtemp);
		}
		break;
		case CTokener::eDevide:
		{
			double value1 = results.top();
			results.pop();
			double value2 = results.top();
			results.pop();
			if (value1 < 1e-6 &&value1 >-1e-6)
			{
				return 0;
			}
			double dtemp = value2 / value1;
			results.push(dtemp);
		}
		break;
		default:
			break;
		}

	}


	double dresult = results.top();
	return dresult;
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值