AcWing 3302 表达式求值
发布日期:2021-05-28 16:29:37 浏览次数:36 分类:精选文章

本文共 2918 字,大约阅读时间需要 9 分钟。

要解决中缀表达式求值问题,我们可以使用栈的数据结构来帮助处理运算符和数字。以下是详细的解决思路:

问题分析:

给定一个中缀表达式,其中运算符包括加法减法乘法除法,并可能包含括号。表达式的合法性由题目保证,因此我们不需要处理错误情况。目标是从左到右逐步计算表达式,利用栈来维护运算符和目前尚未处理的数字,依次计算表达式的值。

核心思路:

  • 初始化栈:使用两个栈,一个用于存储运算符(运算符栈),另一个用于存储暂时的数字(数字栈)。
  • 扫描输入表达式:从左到右遍历每个字符,处理数字和运算符。
    • 处理数字:将连续的数字字符拼接成整数,然后压入数字栈。
    • 处理运算符
      • 如果运算符是一个括号,左括号直接压入运算符栈,右括号则处理括号内所有运算。
      • 对于加减操作,如果当前运算符的优先级低于栈顶运算符,弹出栈顶运算符并进行计算。
      • 对于乘除操作,优先于加减,同样的处理方式。
    • 处理右括号:处理括号内的所有运算,直到找到左括号,并弹出左括号,继续处理后续运算。
  • 处理未处理的数字:表达式的最终可能以一个数字结尾,此时需要将其压入数字栈。
  • 处理剩余运算符栈中的运算:扫描结束后,如果运算符栈不为空,继续弹出并计算,直到栈为空。
  • 具体步骤:

  • 初始化

    • 运算符栈和数字栈都初始化为空。
    • 设定各运算符的优先级,例如,乘除的优先级高于加减,左括号优先级最低。
  • 扫描字符

    • 对于每个字符,判断是否为数字或运算符:
      • 如果是数字,将其暂存到一个变量中,继续扫描下一个字符。如果是运算符,检查之前的数字是否需要入栈处理。
      • 如果是运算符,比较栈顶运算符的优先级,决定是否需要计算。
      • 处理括号时,改变当前运算符的优先级,确保括号正确闭合。
  • 处理运算符

    • 保持栈中运算符的优先级顺序,确保正确的运算顺序。
    • 弹出栈顶的运算符并计算,与当前运算符比较优先级,如优先级低则继续返回。
  • 计算最终结果

    • 扫描完成后,处理未处理的数字和运算符栈中的剩余运算,得到最终结果。
  • 示例分析:

    举个例子,表达式为 1+2*3-4/2

    • 遍历时,遇到1,暂存到数字栈。
    • 遇到+,检查栈条件,确定运算符优先级,继续。
    • 遇到2,暂存,遇到*,由于的优先级高于栈顶的+,弹出2,计算23=6。
    • 接下来扫描到-,弹出栈中的议,处理后续运算。

    代码实现:

    以下是一个可能的C++实现,将其余部分的代码块化为函数:

    #include 
    #include
    using namespace std;stack
    numStack;stack
    opStack;string s;// 定义运算符优先级:lower表示低于,higher表示高于bool cmp(char c1, char c2) { if (c1 == '(' || c2 == '(') return false; if (c1 == '+' || c1 == '-') { return c2 != '*' && c2 != '/'; } else if (c1 == '*' || c1 == '/') { return c2 == '*' || c2 == '/'; } return false;}void compute() { int a = numStack.top(); numStack.pop(); int b = numStack.top(); numStack.pop(); char c = opStack.top(); opStack.pop(); if (c == '+') { numStack.push(a + b); } else if (c == '-') { numStack.push(b - a); } else if (c == '*') { numStack.push(a * b); } else if (c == '/') { if (b > 0) { int result = b / a; numStack.push(result); } else { // 处理负数取整 numStack.push((b - 1) / a + 1); } }}int main() { cin >> s; int n = 0; for (int i = 0; i < s.size(); i++) { if (isdigit(s[i])) { n = n * 10 + (s[i] - '0'); } else { // 处理数字 if (i > 0 && isdigit(s[i-1])) { numStack.push(n); n = 0; } // 处理运算符或括号 if (s[i] == '(') { opStack.push(s[i]); } else if (s[i] == ')') { while (opStack.top() != '(') { compute(); } opStack.pop(); // 消除左括号 } else { // 遇到运算符,开始处理 while (!opStack.empty() && cmp(s[i], opStack.top())) { compute(); } opStack.push(s[i]); } } } // 处理剩下的数字 if (n != 0) { numStack.push(n); } // 计算完罢了所有运算符 while (!opStack.empty()) { compute(); } cout << numStack.top();}

    总结:

    通过实现上述逻辑,我们能够正确地处理中缀表达式,计算出其值。代码中详细处理了括号运算、运算符的优先级以及取整规则,确保结果正确。

    上一篇:POJ1753 Flip Game
    下一篇:AcWing 2816 判断子序列

    发表评论

    最新留言

    做的很好,不错不错
    [***.243.131.199]2025年04月20日 04时54分49秒