中置式の評価(スタックの適用)

トピック:
式の評価

質問の意味:
長さが1 0 5 10 ^ 5を超えない場合1 05の式、この式の値を見つけてください。
デジタル演算処理を直接デジタルネガを得られないことを確認し、そしてのみ+-*/()この666種類のキャラクター。
データ範囲:∣s∣≤10 5 | s | \ leq 10 ^ 5s 1 05

解決策:
ここでは、加算と減算add、および乗算と除算を呼び出しますmul
減算は数値と負の数に変換できるため、除算の分母は分母のモジュラスの下で逆元に変換できます。

通常括弧なしで中置式評価することを考慮してください。次のように約4つの状況があります。

  • addadda+b+dそして、私たちが最初に計算することができa+b=c、その後、計算c+dすることができます。
  • mulmula*b*dそして、私たちが最初に計算することができa*b=c、その後、計算c*dすることができます。
  • muladda*b+dそして、私たちが最初に計算することができa*b=c、その後、計算c+dすることができます。
  • add、後mula+b*d今回より高い数値が優先に、私たちは、乗算の結果を取得する必要がありb*d=c、その後、計算しますa+c

最初の3つのケースを見ることができます。前一个计算符号優先度が優先度より后一个计算符号低くない場合は、直接計算でき、計算結果は次の式に代入されて計算されます。ときに前一个计算符号、優先度がより低い后一个计算符号優先順位、それだけのために待つことができる后一个计算符号計算結果と、その後の計算を行います。
要約すると、シンボルの優先度を厳密に単調に増加させて単調なスタックを維持することを検討できます。スタックには最大で2つの要素しかなく、スタックの最下部はプラス記号またはマイナス記号。上部は乗算記号または除算記号です。


次に、角かっこを使用した計算について考えます。
角かっこは、式の優先順位を上げるための記号ですが、実際の加算、減算、乗算、および除算の計算は実行しません。
約3つの中置式に対応します。

  • add/mul()a*(b+c)等...
    前回のこの計算式addポストはmul同じですが、私たちは、括弧内の式の値を計算する必要があります。したがって、いずれの場合も(、スタックにプッシュできる必要があり、スタック内の計算は通常の計算と同じです。

  • before (after )(a+b)など...
    実際、これは括弧内の式が評価され、)時間に遭遇すると、を示し、対応する角かっこ式の角かっこ間の式)と一致し(ます。このとき、角かっこ計算結果を取得するには、式を計算する必要があります。
    開き括弧のため、どのような場合でもスタックできることに注意してください。そのため、スタックが発生した場合、((a+b))または(a+(b*c+d))そのような場合、スタック後のスタックは、厳密に単調に増加するスタック属性を満たさなくなります。したがって、ここに単調なスタックがあります。左括弧が存在するため、単調増加は完全ではなくなりますが、計算シンボルシーケンスの区切り文字としての左括弧2つごとに、厳密な単調増加が個別に満たされます。もちろん、これらのシンボルシーケンスの長さは長くなりません。22より2スタック
    として(、式の任意の符号をスタックにプッシュすることができ、その優先順位は最小限に抑えられると述べています。
    与えられた式(の最初と最後に1つずつ追加して、)説明全体の整合性確保すると同時に、計算​​を個別に解決する必要がないようにすることができます。具体的a+bには、スタックの構築後にスタックを個別に操作する必要があります。最初と最後に括弧を追加すると、実装がより美しくなります。

  • ()add/mul(a+b)*cこのオペアンプmulの後にadd計算、それらを繰り返すことはしません。


この質問は、負の数は存在しないことを説明していますが、特定の負の数とマイナス記号の2つのタイプを区別する方法はまだあります。マイナス記号として機能する
場合を検討してください-

  • ときに-フロントがある)とき
  • ときに-フロントは数値です

これらは両方とも-、結果が代入された後の式の計算として前の式を直接計算できることを示しています。これは、計算記号の中で最も低いマイナス記号の優先度によって決定されます。

コード:
このコードは2 31 − 1 2 ^ {31} -1をサポートします23 11以内の負の数で加算、減算、乗算、除算し、括弧内に計算します。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

const int N = 1e5 + 10;
char op[N]; int topo;
int num[N]; int topn;
char s[N];
int n;

int cal(char ch) {
    
    
    int b = num[topn--];
    int a = num[topn--];
    if(ch == '+') return a + b;
    else if(ch == '-') return a - b;
    else if(ch == '*') return a * b;
    return a / b;
}

int level(char ch) {
    
    
    if(ch == '(') return 0;
    else if(ch == '+' || ch == '-') return 1;
    return 2;
}

bool check_f(int i) {
    
    
    if(i > 2 && (isdigit(s[i - 1]) || s[i - 1] == ')')) return false;
    return true;
}

int main()
{
    
    
    scanf("%s", s + 2);
    n = strlen(s + 2) + 2;
    s[1] = '(', s[n] = ')';
    for(int i = 1; i <= n; ++i) {
    
    
        if(isdigit(s[i]) || (s[i] == '-' && check_f(i))) {
    
    
            int c = 0, f = 1;
            if(s[i] == '-') f = -1, ++i;
            while(i <= n && isdigit(s[i])) c = c * 10 + s[i] - '0', ++i;
            num[++topn] = c * f;
            --i;
        }
        else {
    
    
            if(s[i] == '(') op[++topo] = s[i];
            else if(s[i] == ')') {
    
    
                while(topo > 0 && op[topo] != '(') {
    
    
                    char ch = op[topo--];
                    int c = cal(ch);
                    num[++topn] = c;
                }
                --topo;
            }
            else {
    
    
                while(topo > 0 && op[topo] != '(' && level(s[i]) <= level(op[topo])) {
    
    
                    char ch = op[topo--];
                    int c = cal(ch);
                    num[++topn] = c;
                }
                op[++topo] = s[i];
            }
        }
    }
    
    printf("%d\n", num[topn]);
    
    return 0;
}

おすすめ

転載: blog.csdn.net/weixin_43900869/article/details/114809135