例子主要实现带括号的+、-、*、/的运算,如“3+(5*5)”的表达式的数值运算。本例是在Dev C++11中编译通过。源码请点击如下链接:
1) 采用map记录+,-,*,/运算:
1.逻辑思路:
1.遇到(,+、-、*、/符号是压入栈中;
2.遇到),弹出栈中表达式进行计算,直到遇到(为止,并将计算总值压入栈中
3.遇到数字,查看栈顶是否为*或/运算符,如果是弹出运算符和数字进行计算再将计算结果压入栈中
4.其他字符跳过
2.实现算法逻辑
①首先定义如下类
class Calculator
{
friend ostream& operator<<(ostream&, Calculator&); //打印表达式和计算结果
public:
Calculator(const string& s):expression(s),cur_pos(0){} //构造函数
void reset(const string& s) { expression=s; }
double calculate(); //计算结果
private:
inline void clear(); //清空
inline double getNumber(); //从cur_pos位置获取expersion表达式中的数值
inline void next(); //移动cur_pos到下一个关键字符
inline CalcType unitType(); //获取cur_pos当前指向的字符类型
inline void calcAll();
inline void calcBracket(); //计算带左括号的运算块
inline double calcTop();
inline void highOper();
private:
size_t cur_pos; //解析表达式的位置
string expression; //存储表达式
typedef pair<CalcType, double> stack_type;
stack<stack_type> opers; //栈
static map<CalcType, function<double (double, double)>> binops; //二目运算操作
static map<string, CalcType> symbol;
static string numbers;
};
②
根据逻辑思路实现calculate
double Calculator::calculate()
{
clear();
do
{
CalcType type = unitType(); //获取当前指向的类型
switch(type)
{
case Calc_Left: //"("压
case Calc_Add:
case Calc_Minus:
case Calc_Muti:
case Calc_Divi:
opers.push(stack_type(type, 0)); //遇到(,+、-、*、/符号是压入栈中;
break;
case Calc_Right:
calcBracket();//遇到),弹出栈中表达式进行计算,直到遇到(为止,并将计算总值压入栈中
break;
case Calc_Number:
highOper();//遇到数字,查看栈顶是否为*或/运算符,如果是弹出运算符和数字进行计算再将计算结果压入栈中
break;
}
next();
}while((cur_pos != string::npos) && (cur_pos < expression.length()));
calcAll();
if(1 != opers.size())
throw logic_error("表达式不正确!");
stack_type result(opers.top());
return result.second;
}
③关键实现
1) 采用map记录+,-,*,/运算:
1)采用map记录+,-,*,/运算:
//定义类静态变量的二目运算map,通过function定义函数指针
map<CalcType, function<double (double, double)>> Calculator::binops =
{{Calc_Add, std::plus<double>()},
{Calc_Minus, std::minus<double>()},
{Calc_Muti, std::multiplies<double>()},
{Calc_Divi, std::divides<double>()}};
//当进行+运算式只需这样操作即可
double result = binops[Calc_Add](2, 1); //result值等于3
②)
采用map实现字符串关键字查找,并通过string.find_first_of()查找数字后通过stod转发为double
//定义不同字符串的具体意思
map<string, CalcType> Calculator::symbol = {{"(",Calc_Left},
{")",Calc_Right},
{"+",Calc_Add},
{"-",Calc_Minus},
{"*",Calc_Muti},
{"/",Calc_Divi}};
CalcType Calculator::unitType()
{ //numbers="0123456789",查询是否为数值
if(cur_pos == expression.find_first_of(numbers, cur_pos))
return Calc_Number;
//通过map查询是关键字符的枚举类型
auto iter = symbol.find(expression.substr(cur_pos, 1));
if(iter == symbol.end())
return Calc_Error;
else
return iter->second;
④运行效果
编写测试函数,打印输出如下所示
int main(int argc, char** argv)
{
Calculator exper("(21-1+10)*((1-2)-1/2)");
cout<< exper << endl;
exper.reset("12 + (4/2)");
cout<< exper << endl;
exper.reset("12 + (4/2) + (3 * 10)");
cout<< exper << endl;
exper.reset("13 + (23*10) - 3 +");
cout<< exper << endl;
exper.reset("13 + (23*10 - 3");
cout<< exper << endl;
exper.reset("13 + 23*10) - 3");
cout<< exper << endl;
return 0;
}
//打印结果
(21-1+10)*((1-2)-1/2) = -15
12 + (4/2) = 14
12 + (4/2) + (3 * 10) = 44
13 + (23*10) - 3 + -> 表达式不正确
13 + (23*10 - 3 -> 表达式不正确
13 + 23*10) - 3 -> 表达式不正确
--------------------------------
Process exited after 0.4188 seconds with return value 0
请按任意键继续. . .
实现源码:
点击打开链接