思路
首先我们需要知道如何转化表达式并求值:首先不同的运算符有不同的优先级:对于(,),优先级最高,其次是*,/,最低是+,-。在从左往右扫描字符串时,遇到数字,就将其直接压入数组中。遇到操作符时,如果当前栈为空,那么直接压入栈中,如果栈不为空,那么将栈顶操作符优先级大于等于当前操作符的操作符pop出栈,并压入数组,直到栈顶操作符优先级小于当前操作符或栈为空才停止此次操作,并将当前操作符压入栈中。
由于在我的代码中遇到左括号是直接递归,右括号return,因此上面的处理中不需要考虑括号。
得到表达式后,我们就需要进行求值,首先我们得到的是一个数组,其中按后缀表达式中的顺序存储着操作符以及数字。那么我们从左往右遍历数组,当遇到数字时,将其压入栈中,遇到操作符时,在栈中提取出两个元素,并将两个元素根据操作符计算得到的值压入栈中,最后栈顶元素即为表达式的值。
代码
#include <iostream>
#include <stack>
#include <string>
#include <vector>
using namespace std;
void showAndPush(vector<string> &expr, const string &s, char t = ' ') {
expr.push_back(s);
cout << s << t;
}
bool isOper(const string &s) { //数组中可能出现-2,+2等元素,因此size()==1为前提。
return s.size() == 1 && (s[0] == '+' || s[0] == '-' || s[0] == '*' || s[0] == '/');
}
int cal(int num, int num1, char oper) {
switch (oper) {
case '+': return num + num1;
case '-': return num - num1;
case '*': return num * num1;
case '/': return num / num1;
}
}
//将输入的中缀表达式转化为后缀表达式
void infixToSuffix(int &p, const string &text, vector<string> &expr) {
stack<char> stk;
int len = text.length(), pre = expr.size();
for (; p < len; ++p) {
switch (text[p]) {
case '+':
case '-':
while (!stk.empty()) {
expr.emplace_back(1, stk.top());
cout << stk.top(); stk.pop();
}
stk.push(text[p]);
break;
case '*':
case '/':
while (!stk.empty() && (stk.top() == '*' || stk.top() == '/')) {
expr.emplace_back(1, stk.top());
cout << stk.top(); stk.pop();
}
stk.push(text[p]);
break;
case '(':
infixToSuffix(++p, text, expr); //遇到左括号就递归,将括号中的表达式当成一个独立的表达式,即可解决优先级的问题
break;
case ')':
while (!stk.empty()) {
showAndPush(expr, string(1, stk.top()));
stk.pop();
}
return;
case ' ': //遇到空格直接跳过不用处理
break;
default:
string num;
if (pre == expr.size() && !stk.empty()) { //这条if语句用于处理-2,(+2)等情况。这种情况下-+不算操作符。
num.push_back(stk.top());
stk.pop();
}
while (isdigit(text[p])) {
num.push_back(text[p]);
++p;
}
--p;
showAndPush(expr, num);
}
}
while (!stk.empty()) { //将栈中剩下的操作符全部压入数组中
showAndPush(expr, string(1, stk.top()));
stk.pop();
}
}
int calculate(const vector<string> &expr) { //根据后缀表达式数组进行求值。
stack<int> num;
for (auto &iter : expr) {
if (isOper(iter)) { //遇到操作符就将栈顶的两个元素出栈并求值,将结果再压入栈中,注意两个元素的顺序。
int t = num.top(); num.pop();
int t1 = num.top(); num.pop();
num.push(cal(t1, t, iter[0]));
} else {
num.push(stoi(iter));
}
}
return num.top(); //栈顶元素即为结果
}
void sln() {
string text;
getline(cin, text);
vector<string> expr;
int p = 0;
infixToSuffix(p, text, expr); //将中缀表达式转化为后缀表达式
cout << endl;
cout << calculate(expr) << endl; //对后缀表达式求值
}
int main() {
sln();
return 0;
}