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) - -6Whitespace 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 //
26 + -(4) // 2 6 + -( -4) // 10 And the following are invalid
expressions1 - - 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;
}