本题要思考的点还是挺多的。首先看到四则运算的括号匹配问题,想要要利用栈来做。这里需要用到两个栈,一个栈用来存放数字,另一个栈用来存放符号。
考虑不同的情况:1. 碰到数字时,直接将数字加入数字栈,注意数字可能有多位数;2. 碰到左括号时,可以全部处理为小括号,直接将左括号加入符号栈,但是需要注意处理左括号后紧跟着负数的情况,这里可以用这样的处理方式:如果后面紧跟着负数,则将0加入的数字栈中;
3. 碰到右括号,则执行计算,直到符号栈的顶部元素不再是左括号为止;4. 碰到符号,则注意不单单需要将符号入栈,还需要根据符号的优先级考虑是否需要执行运算。如果已经入栈的栈顶元素符号的优先级大于或者等于即将入栈的这个符号,则需要先执行那个优先级更高或相等的运算,直到新加入的符号的优先级大于符号栈栈顶的元素。然后将该符号加入栈中。遍历完表达式后,还可能还有运算没有执行完,但是此时的优先级肯定只剩下从右到左,所以直接执行计算即可。
#include <iostream>
#include <stack>
#include <unordered_map>
#include <string.h>
using namespace std;

bool isNum(char ch) {
    if (ch >= '0' && ch <= '9') return true;
    else return false;
}

void cal(stack<int> &nums, stack<char> &symbols) {
    int num1 = nums.top();
    nums.pop();
    int num2 = nums.top();
    nums.pop();
    char ch = symbols.top();
    symbols.pop();
    int ans = 0;
    // 注意是num2对num1的操作
    switch (ch) {
        case '+': { ans = num2 + num1; break; }
        case '-': { ans = num2 - num1; break; }   
        case '*': { ans = num2 * num1; break; }    
        case '/': { ans = num2 / num1; break; }    
    }
    nums.push(ans);
}

int main() {
    string s;
    getline(cin, s, '\n');
    unordered_map<char,int> priority;  // 保存运算符的优先级
    // 设置运算符的优先级
    priority['('] = 0; priority[')'] = 0; priority['+'] = 1; priority['-'] = 1; priority['*'] = 2; priority['/'] = 2;
    stack<char> symbols;  // 符号栈
    stack<int> nums;      // 数字栈
    if (s[0] == '-') nums.push(0);   // 考虑到第一个数字为负数的情况
    for (int i = 0; i < s.size(); i++) {
        // 碰到数字
        if (isNum(s[i])) {
            int left = i;
            int right = left;
            while (isNum(s[right + 1])) {
                right++;
            }
            i = right;   // 注意这里要更新i的值
            nums.push(stoi(s.substr(left, right - left + 1)));
            
        } else if (s[i] == '(' || s[i] == '[' || s[i] == '{') {
            // 碰到左括号,直接入栈
            if (i != s.size() - 1) { if (s[i + 1] == '-') nums.push(0); }  // 需要考虑左括号后紧跟一个负数的情况,例如 (-4+5)}
            symbols.push('(');  // 所有的括号类型都按照小括号处理
            
        } else if (s[i] == ')' || s[i] == ']' || s[i] == '}') {
            // 遇到右括号,执行括号内的运算
            while (symbols.top() != '(') {
                cal(nums, symbols);
            }
            symbols.pop();  // 将左括号出栈
            
        } else {
            // 碰到的是符号
            while (!symbols.empty() && priority[s[i]] <= priority[symbols.top()]) {
                // 如果已经入栈的符号的优先级大于即将入栈的符号,则把前一个优先级更高的运算执行了,
                cal(nums, symbols);
            }
            symbols.push(s[i]);  // 将符号入栈
        }
    }
    // 运算没有结束,其实剩下的运算优先级肯定是从右到左
    while (!symbols.empty()) {   
        cal(nums, symbols);
    }
    cout << nums.top() << endl;
    return 0;
}