注意:下面的实现默认传入的表达式是合法的,在计算过程中没有对表达式的正确性检验。
方法:遍历表达式,根据不同的情况进行不同处理:
- 如果遇到数字,就压入栈中
- 如果遇到运算符,判断是单目还是双目运算符:
(a) 单目:从栈取出1
个操作数进行运算,并将结果再次存入栈中
(b) 双目:从栈取出2
个操作数进行运算,并将结果再次存入栈中 - 遍历结束后,栈中剩下一个数,就是结果
主要逻辑
实现主要逻辑的函数:
double evaluate(const string& expression) {
stack<double> s; // 存数的栈
int i = 0; // 遍历用的下标
int len = expression.length();
double result = 0; // 表达式结果
while (i < len) { // 遍历
if (isdigit(expression[i])) { // 如果是数字,就存入栈
double operand = get_operand(expression, i);
s.push(operand);
}
else if (expression[i] == '!') { // 如果是单目运算符,就取1个数计算
double operand = s.top();
s.pop();
s.push(operate('!', operand)); // 结果存回栈中
}
else { // 如果是双目运算符,就取2个数计算
// !注意取数和运算时传入的顺序!
double operand2 = s.top();
s.pop();
double operand1 = s.top();
s.pop();
s.push(operate(expression[i], operand1, operand2)); // 结果存回栈中
}
i++;
}
return s.top();
}
在上面的主要逻辑中封装了一些辅助函数,使得主要逻辑比较清晰,下面给出这些辅助函数:
辅助函数们
从字符串中获取数字
字符串中的数字可能为多位且为浮点数,因此可能需要连续的取字符以获得一个完整的数,要注意的是传入的下标i
为引用。
使用了std::stod()
进行string
向double
的转换。
double get_operand(const string& expression, size_t& i) {
string operand = "";
int len = expression.length();
while (isdigit(expression[i]) && i < len) {
operand.push_back(expression[i++]);
}
return stod(operand);
}
计算阶乘
int factorial(int n) {
int result = 1;
for (int i = 2; i <= n; ++i) result *= i;
return result;
}
单目运算符计算
这里现在还只有!
阶乘这一个运算符,你也可以自行添加。
int operate(char unary_operator, double operand) {
int result;
switch (unary_operator) {
case '!':
result = factorial((int)operand);
break;
}
return result;
}
双目运算符计算
在%
和^
运算中使用了std::fmod()
和std::pow()
。
double operate(char binary_operator, double operand1, double operand2) {
double result;
switch (binary_operator) {
case '+':
result = operand1 + operand2;
break;
case '-':
result = operand1 - operand2;
break;
case '*':
result = operand1 * operand2;
break;
case '/':
result = operand1 / operand2;
break;
case '%':
result = fmod(operand1, operand2);
break;
case '^':
result = pow(operand1, operand2);
break;
}
return result;
}