You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
python/TangDou/CSP-J/J1_2022/表达式转换与表达式求值.md

6.5 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

题目传送门

第四题还没看

表达式转换与表达式求值

一、四则运算

中缀转后缀

/*
比如:
a+b*c+(d*e+f)*g

应输出:
abc*+de*f+g*+
*/
#include <iostream>
#include <cstring>
#include <stack>
#include <unordered_map>

using namespace std;

unordered_map<char, int> h{{'+', 1}, {'-', 1}, {'*', 2}, {'/', 2}, {'(', 0}};
string infix;   //输入的中缀表达式
string postfix; //后缀的结果表达式
stack<char> s;  //使用到的操作符+数字栈,这里的数字不用真的计算,所以统一按字符处理

int main() {
    cin >> infix;
    for (int i = 0; i < infix.size(); i++) {
        //是数字或字母的情况,直接记录到后缀表达式中
        if (isdigit(infix[i]) || (infix[i] >= 'a' && infix[i] <= 'z'))
            postfix += infix[i];
        else {
            //① 栈为空时直接入栈
            if (s.empty()) s.push(infix[i]);
            //② 左括号入栈
            else if (infix[i] == '(')
                s.push(infix[i]);
            //③ 如果是右括号,就在栈中不断弹出操作符和数字,直到栈顶是(为止
            else if (infix[i] == ')') {
                while (s.top() != '(') {
                    postfix += s.top();
                    s.pop();
                }
                //弹出左括号,但不输出
                s.pop();
            } else {
                //④栈顶元素的优先级大于等于当前的运算符,就将其输出
                while (s.size() && h[infix[i]] <= h[s.top()]) {
                    postfix += s.top();
                    s.pop();
                }
                //⑤当前运算符入栈
                s.push(infix[i]);
            }
        }
    }
    //⑥ 如果不为空,就把所有的元素全部弹出
    while (s.size()) {
        postfix += s.top();
        s.pop();
    }
    //输出后缀表达式
    cout << postfix << endl;
    return 0;
}

后缀表达式求值

#include <iostream>
#include <stack>
#include <string>
#include <unordered_map>
//下面的代码实现了由中缀表达式求值的过程
using namespace std;

/*
测试用例I
(2+2)*(1+1)

答案8

测试用例II
2+(3*4)-((5*9-5)/8-4)

答案13

*/

stack<int> num; //数字栈
stack<char> op; //操作符栈

//优先级表
unordered_map<char, int> h{{'+', 1}, {'-', 1}, {'*', 2}, {'/', 2}, {'(', 0}};

/**
 * 功能:计算两个数的和差积商
 */
void eval() {
    int a = num.top(); //第二个操作数
    num.pop();

    int b = num.top(); //第一个操作数
    num.pop();

    char p = op.top(); //运算符
    op.pop();

    int r = 0; //结果
    //计算结果
    if (p == '+')
        r = b + a;
    else if (p == '-')
        r = b - a;
    else if (p == '*')
        r = b * a;
    else if (p == '/')
        r = b / a;
    //结果入栈
    num.push(r);
}

int main() {
    //读入表达式
    string s;
    cin >> s;
    //遍历字符串的每一位
    for (int i = 0; i < s.size(); i++) {
        //① 如果是数字,则入栈
        if (isdigit(s[i])) {
            //读出完整的数字
            int x = 0;
            while (i < s.size() && isdigit(s[i])) {
                x = x * 10 + s[i] - '0';
                i++;
            }
            i--; //加多了一位,需要减去

            num.push(x); //数字入栈
        }
        //② 左括号无优先级,入栈
        else if (s[i] == '(')
            op.push(s[i]);
        //③ 右括号时,需计算最近一对括号里面的值
        else if (s[i] == ')') {
            //从栈中向前找,一直找到左括号
            while (op.top() != '(') eval(); //将左右括号之间的计算完,维护回栈里
            //左括号出栈
            op.pop();
        } else { //④ 运算符
            //如果待入栈运算符优先级低,则先计算
            while (op.size() && h[op.top()] >= h[s[i]]) eval();
            op.push(s[i]); //操作符入栈
        }
    }
    while (op.size()) eval(); //⑤ 剩余的进行计算

    printf("%d\n", num.top()); //输出结果
    return 0;
}

二、逻辑运算

中缀转后缀

//下面的代码实现了中缀的逻辑表达式 转 后缀的逻辑表达式
#include <iostream>
#include <cstring>
#include <stack>
#include <unordered_map>

using namespace std;
/*
测试用例:
0&(0|1|0)

答案:
001|0|&
*/
unordered_map<char, int> h{{'|', 1}, {'&', 2}, {'(', 0}};
string infix;   //输入的中缀表达式
string postfix; //后缀的结果表达式
stack<char> s;  //使用到的操作符+数字栈,这里的数字不用真的计算,所以统一按字符处理

int main() {
    cin >> infix;
    for (int i = 0; i < infix.size(); i++) {
        //是数字或字母的情况,直接记录到后缀表达式中
        if (isdigit(infix[i]) || (infix[i] >= 'a' && infix[i] <= 'z'))
            postfix += infix[i];
        else {
            //① 栈为空时直接入栈
            if (s.empty()) s.push(infix[i]);
            //② 左括号入栈
            else if (infix[i] == '(')
                s.push(infix[i]);
            //③ 如果是右括号,就在栈中不断弹出操作符和数字,直到栈顶是(为止
            else if (infix[i] == ')') {
                while (s.top() != '(') {
                    postfix += s.top();
                    s.pop();
                }
                //弹出左括号,但不输出
                s.pop();
            } else {
                //④栈顶元素的优先级大于等于当前的运算符,就将其输出
                while (s.size() && h[infix[i]] <= h[s.top()]) {
                    postfix += s.top();
                    s.pop();
                }
                //⑤当前运算符入栈
                s.push(infix[i]);
            }
        }
    }
    //⑥ 如果不为空,就把所有的元素全部弹出
    while (s.size()) {
        postfix += s.top();
        s.pop();
    }
    //输出后缀表达式
    cout << postfix << endl;
    return 0;
}

后缀表达式求值

(1,a_1,b_1) | (?,a_2,b_2) \Rightarrow (1,a_1,b_1+1)

(0,a_1,b_1) | (?,a_2,b_2) \Rightarrow (?,a_1+a_2,b_1+b_2)

(1,a_1,b_1) \& (?,a_2,b_2) \Rightarrow (?,a_1+a_2,b_1+b_2)

(0,a_1,b_1) \& (?,a_2,b_2) \Rightarrow (0,a_1+1,b_1)