字符串四则运算

字符串的四则运算,可以将字符串表示的中缀表达式转换为后缀表达式(逆波兰表示法, Reverse Polish Notation),然后对后缀表达式进行求解。

中缀->后缀:

利用栈来处理操作符的优先顺序。具体为在中缀表达式中如果遇到了数字,则直接输出,如果遇到了操作符s,则将其与栈中的操作符比对,如果该操作符的优先级小于等于栈顶操作符的优先级,则将栈顶中的操作符依次出栈输出,直到栈顶的操作符小于该操作符s,并将其入栈。如果遇到了右括号,则将栈中元素弹出直到遇到左括号。

后缀表达式求值:

将数字直接压入栈中,如果遇到操作符,则将栈顶num1和次栈顶num2依次弹出,对num2num1进行四则运算,并将结果压入栈中,重复以上步骤,直到后缀表达式中的各个元素都处理过了。

#include<iostream>
#include<vector>
#include<string>
#include<algorithm>
#include<sstream>
#include<stack>
using namespace std;

// 中缀表达式转后缀表达式,返回的表达式中用不定数的空格将操作数(或操作符)和操作符(或操作数)分开
string getRPN(string s) {
    stack<char> sk;
    string res;
    int n = s.size();
    for (int i = 0; i < n; ++i) {
        while (i < n && isdigit(s[i])) {
            res += s[i++];
        }
        res += ' ';
        if (i == n) break;
        if (s[i] == '+' || s[i] == '-') {
            // 将栈顶中所有优先级大于等于'+','-'的操作符依次弹出,最后将当前操作符入栈
            while (!sk.empty()) {
                if (sk.top() == '+' || sk.top() == '-' || sk.top() == '*' || sk.top() == '/') {
                    res += ' ';  // 先加空格
                    res += sk.top();
                    sk.pop();
                }
                else
                    break;
            }
            sk.push(s[i]);
        }
        else if (s[i] == '*' || s[i] == '/') {
            while (!sk.empty()) {
                if (sk.top() == '*' || sk.top() == '/') {
                    res += ' ';
                    res += sk.top();
                    sk.pop();
                }
                else
                    break;
            }
            sk.push(s[i]);
        }
        else if (s[i] == '(') {
            sk.push('(');
        }
        else if (s[i] == ')') {
            // 将配对左括号之间的全部操作符依次输出
            while (!sk.empty() && sk.top() != '(') {
                res += ' ';
                res += sk.top();
                sk.pop();
            }
            sk.pop();  // 将左括号弹出
        }
        else
            continue;  // 跳过空格之类的
    }
    // 将栈中剩余的操作符依次全部弹出
    while (!sk.empty()) {
        res += ' ';
        res += sk.top();
        sk.pop();
    }
    return res;
}

// 计算后缀表达式的值
int calStr(const string& src) {
    stringstream ss(src);
    string s;
    stack<int> sk;
    int res = 0;
    while (ss >> s) {
        // 如果遇到数字,则压入栈中
        if (isdigit(s[0])) {
            sk.push(stoi(s));
        }
        else {
            // 如果遇到操作符,则弹出栈顶的两个元素,计算后将结果再入栈
            int num1 = sk.top(); sk.pop();
            int num2 = sk.top(); sk.pop();
            if (s == "+") res = num2 + num1;
            if (s == "-") res = num2 - num1;
            if (s == "*") res = num2 * num1;
            if (s == "/") res = num2 / num1;
            sk.push(res);
        }
    }
    return res;
}

int main()
{
    string s = "90 - 30 + ((220 * (12 + (333 - 19) / 3)) + 498) * 31 + 108 / 3";
    string rpn_s = getRPN(s);
    cout << calStr(rpn_s) << endl;
    cout << 90 - 30 + ((220 * (12 + (333 - 19) / 3)) + 498) * 31 + 108 / 3 << endl;
    return 0;
}
90   30   -   220    12    333   19  -   3  / +  *   498  +   31   * + 108   3  / +
806654
806654

解法2:

int calculate(string s) {
    int res = 0, cur_res = 0, num = 0;
    char op = '+';
    s += '+';
    for (int i = 0; i < s.size(); ++i) {
        char c = s[i];
        if (isdigit(c))
            num = num * 10 + c - '0';
        else if (c == '(') {
            // 将括号中的子字符串作为一个表达式
            int left = i;
            int cnt = 0;  // 保证括号能够匹对的上
            for (; i < s.size(); ++i) {
                if (s[i] == '(') ++cnt;
                if (s[i] == ')') --cnt;
                if (cnt == 0) break;
            }
            num = calculate(s.substr(left + 1, i - left + 1 - 2));
        }
        else if (c == '+' || c == '-' || c == '*' || c == '/') {
            switch (op)  // 使用的是op,不是c
            {
            case '+': cur_res += num; break;
            case '-': cur_res -= num; break;
            case '*': cur_res *= num; break;
            case '/': cur_res /= num; break;
            }

            if (c == '+' || c == '-') {
                res += cur_res;
                cur_res = 0;
            }
            op = c;
            num = 0;
        }
    }
    return res;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值