表达式求值有几个核心的技术:
1 中缀infix表达式转后缀postfix表达式(文本解析)
解析中缀表达式到后缀表达式的核心思想就是对表达式逐步向前解析;
如果遇到一个空格就连续“吃掉”紧接着的空格;
如果遇到一个操作数就“继续吃掉紧接着的整数中的低位数字,完整一个完整整数的读取;
如果遇到了不应该出现的字符就抛出异常。
1.1 运算符操作优先级(使用整形作为特征值)
本文给出的方法简洁有效(比那个二维数组扯淡玩意儿高效简洁了不知道多少)
1.2 吃掉表达式中的任意空格和整数
2 后缀表达式求值(利用栈来快速求值)
类图
1 中缀infix表达式转后缀postfix表达式(文本解析)
//把中缀表达式转换为后缀表达式,返回后缀表达式的长度(包括空格)
void Calculator::ToPostfix(const string& pre , Expression& _postExpression)
{
CStack operatorStack;
operatorStack.push('#');
auto preItr = pre.begin() ;
auto end = pre.end();
string strNumber;
while(preItr != pre.end())
{
ReadSpace(preItr, end);// space before expression
strNumber.clear();
if(isdigit(*preItr))
{
ReadNumber(preItr, end, strNumber); // read number 1
_postExpression.push_back(strNumber);
}
else if (*preItr=='(') // 遇到“(”不用比较直接入栈
{
operatorStack.push(*preItr++);
}
else if(*preItr ==')') // 遇到右括号将其对应左括号后的操作符(操作符栈中的)全部写入后缀表达式
{
while(operatorStack.top()!='(')
{
_postExpression.push_back(string(1,operatorStack.pop()));
}
operatorStack.pop(); // discard '('
++preItr;//discard ')'
}
else if (IsOperator(*preItr))
{
while(Priority(*preItr) <= Priority(operatorStack.top()))
{
// 当前的操作符小于等于栈顶操作符的优先级时,将栈顶操作符写入到后缀表达式,重复此过程
_postExpression.push_back(string(1, operatorStack.pop()));
}
operatorStack.push(*preItr++); // 当前操作符优先级大于栈顶操作符的优先级,将该操作符入栈
}
else if (!isspace(*preItr))//Extra credit 1 for invalid input
{
throw CExpressionException("invalid input, character not supported!");
}
}
while(!operatorStack.empty()) // 将所有的操作符加入后缀表达式
{
if (operatorStack.top() == '(')
{
throw CExpressionException("invalid input in expression, missing ')'!");
}
_postExpression.push_back(string(1, operatorStack.pop()));
}
_postExpression.pop_back();//discard #
}
2 后缀表达式求值(利用栈来快速求值)
int Calculator::GetValue(void) const
{
if (m_infix.empty())
{
throw CExpressionException("no infix expression in Calculator!");
}
Expression post;
ToPostfix(m_infix, post);
CStack stack; // 操作数栈
int x1, x2;
auto itr = post.begin();
while(itr != post.end())
{
if(!IsOperator((*itr)[0]))
{
stack.push(std::stoi(*itr));
}
else if ((*itr)[0] =='+')
{
x2 = stack.pop();
x1 = stack.pop();
stack.push(x1+x2);
}
else if ((*itr)[0] =='-')
{
x2 = stack.pop();
x1 = stack.pop();
stack.push(x1-x2);
}
else if ((*itr)[0] =='*')
{
x2 = stack.pop();
x1 = stack.pop();
stack.push(x1*x2);
}
else if ((*itr)[0] =='/')
{
x2 = stack.pop();
x1 = stack.pop();
stack.push(x1/x2);
}
else if ((*itr)[0] =='%')
{
x2 = stack.pop();
x1 = stack.pop();
stack.push(x1%x2);
}
else if ((*itr)[0] == '^')
{
int power = 1;
x2 = stack.pop();
x1 = stack.pop();
for (int i = 0; i < x2; ++i)
{
power *= x1;
}
stack.push(power);
}
++itr;
}
return stack.top();
}
3 运算符操作优先级(使用整形作为特征值)
int Calculator::Priority(char op)
{
switch(op)
{
case '#':
return -1;
case '(':
return 0;
case '+':
case '-':
return 1;
case '*':
case '/':
case '%':
return 2;
case '^':
return 3;
default :
return -1;
}
}
上面的代码中其中第一个表达式解析的核心思想就是对表达式逐步向前解析,根据已经捕获的表达式预期后续表达式内容,如果不符合就抛出异常。为了能够更好的表达代码和思路,封装几个必要的“吃掉”表达式中指定子结构的函数是必要的。
例如吃掉表达式中的任意空格和整数
4 吃掉表达式中的任意空格和整数
void Calculator::ReadSpace(string::const_iterator& _itr, string::const_iterator& _end)
{
while(_itr != _end)
{
if (isspace(*_itr))
{
++_itr;
}
else
{
break;
}
}
}
void Calculator::ReadNumber(string::const_iterator& _itr, string::const_iterator& _end, string& _value)
{
while(_itr != _end)//read number as 275
{
if (isdigit(*_itr))
{
_value.push_back(*_itr++);
}
else
{
break;
}
}
}
5 测试程序:
#include
#include
#include
#include
using namespace std;
#include "Stack.h"
#include "Calculator.h"
void Input(list& listCalculator);
void Output(const list& listCalculator);
void TestAll(list& listCalculator);
int main(int argc, char** argv)
{
cout<<"Please input some expressions with one expression in one line:"< listCalculator;
TestAll(listCalculator);
//Input(listCalculator);//Extra credit 1:(1)any space (2)catch invalid input
//Output(listCalculator);
return 0;
}
void Input(list& listCalculator)
{
while (true)
{
string sLine, invalidInfor;
getline(cin, sLine);
if (sLine == "0")
{
break;
}
if (Calculator::Check(sLine, invalidInfor) == false)//Extra credit 1:(1)any space (2)catch invalid input
{
cout<& listCalculator)
{
cout<<"infix list:"<GetExpression()<ToPostfix()<GetValue()<& listCalculator)
{
list listExp;
listExp.push_back("(5+1) * ( 2 + 3");
listExp.push_back("(5+1) * ( 2 + 3)");
listExp.push_back("(5+(1+1)) * ( 2 + 3)");
listExp.push_back("1++1");
listExp.push_back("1&1");
listExp.push_back("17 / ( 2 + 3 ) - 13");
listExp.push_back("5 * 2 ^ 3");
listExp.push_back("1+ (2-3)*4 ^5%6 / 78");
for (auto itr = listExp.begin(); itr != listExp.end(); ++itr)
{
string invalidInfor;
if (Calculator::Check(*itr, invalidInfor) == false)//Extra credit 1:(1)any space (2)catch invalid input
{
cout<
运行结果: