其他分享
首页 > 其他分享> > 表达式求值的双栈原理

表达式求值的双栈原理

作者:互联网

转载:AcWing 3302. 表达式求值:多图讲解运算符优先级+详细代码注释 - AcWing  

题目:3302. 表达式求值 - AcWing题库

先看下只有 + 和 * 的。

输入长度为n的字符串,例如:1+2+3*4*5

输出表达式的值,即:63

应该用什么数据结构?

栈。

应该先计算哪一步?

实际应该先计算1+2。

“表达式求值”问题,两个核心关键点:

(1)双栈,一个操作数栈,一个运算符栈;

(2)运算符优先级,栈顶运算符,和,即将入栈的运算符的优先级比较:

如果栈顶的运算符优先级低,新运算符直接入栈

如果栈顶的运算符优先级高,先出栈计算,新运算符再入栈

仍以1+2+3*4*5举例,看是如何利用上述两个关键点实施计算的。

首先,这个例子只有+和*两个运算符,所以它的运算符表是:

 

 这里的含义是:

(1)如果栈顶是+,即将入栈的是+,栈顶优先级高,需要先计算,再入栈;

(2)如果栈顶是+,即将入栈的是*,栈顶优先级低,直接入栈;

(3)如果栈顶是*,即将入栈的是+,栈顶优先级高,需要先计算,再入栈;

(4)如果栈顶是*,即将入栈的是*,栈顶优先级高,需要先计算,再入栈;

有了运算符表,一切就好办了。

 

 

一开始,初始化好输入的字符串,以及操作数栈,运算符栈。

 

 

一步步,扫描字符串,操作数一个个入栈,运算符也入栈。

 

 

下一个操作符要入栈时,需要先比较优先级。

栈内的优先级高,必须先计算,才能入栈。

 计算的过程为:

(1)操作数出栈,作为num2;

(2)操作数出栈,作为num1;

(3)运算符出栈,作为op;

(4)计算出结果;

 

 

(5)结果入操作数栈;

 

 

接下来,运算符和操作数才能继续入栈。下一个操作符要入栈时,继续比较与栈顶的优先级。

栈内的优先级低,可以直接入栈。

 

 

字符串继续移动。

 

 

又要比较优先级了。

 

 

栈内的优先级高,还是先计算(3*4=12),再入栈。

 

 

不断入栈,直到字符串扫描完毕。

 


不断出栈,直到得到最终结果3+60=63,算法完成。

总结

“表达式求值”问题,两个核心关键点:

(1)双栈,一个操作数栈,一个运算符栈;

(2)运算符优先级,栈顶运算符,和,即将入栈的运算符的优先级比较:
如果栈顶的运算符优先级低,新运算符直接入栈

如果栈顶的运算符优先级高,先出栈计算,新运算符再入栈

这个方法的时间复杂度为O(n),整个字符串只需要扫描一遍。

运算符有+-*/()~^&都没问题,如果共有n个运算符,会有一个n*n的优先级表。

代码如下:

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
stack<int> num;
stack<char> op;
unordered_map<char, int> h{{'+', 1}, {'-', 1}, {'*', 2}, {'/', 2}};
void eval()
{
    int a = num.top();
    num.pop();
    int b = num.top();
    num.pop();
    char c = op.top();
    op.pop();
    if (c == '+')
        num.push(a + b);
    if (c == '-')
        num.push(b - a);
    if (c == '/')
        num.push(b / a);
    if (c == '*')
        num.push(a * b);
}
int main()
{
    string s;
    cin>>s;
    for(int i=0;i<s.size();i++)
    {
        if(isdigit(s[i]))
        {
            int x=0,j=i;
            while(j<s.size()&&isdigit(s[j]))
            {
                x=x*10+s[j]-'0';
                j++;
            }
            num.push(x);
            i = j - 1;
        }
        else
        {
            if(s[i]=='(')
                op.push(s[i]);
            else if(s[i]==')')
            {
                while(op.top()!='(')
                    eval();
                op.pop();
            }
            else
            {
                while(!op.empty()&&h[op.top()]>=h[s[i]])
                    eval();
                op.push(s[i]);
            }
        }
    }
    while(!op.empty())    eval();
    cout<<num.top()<<endl;
}

 

标签:操作数,优先级,入栈,栈顶,双栈,运算符,num,求值,表达式
来源: https://www.cnblogs.com/yixinrujiu/p/15350152.html