C++
 Computer >> コンピューター >  >> プログラミング >> C++

C++でネストした三項式を解析する:スタックを使ったパーサーの実装

任意の深さでネストされた三項式(三項演算子による条件式)を表す文字列が与えられたとき、その式を解析して最終的な評価結果を求めるのが本問題です。入力となる式は常に有効であり、構成要素は数字「0〜9」、「?」、「:」、「T」、「F」のみです(TとFはそれぞれTrue・Falseを表します)。この問題には以下のような性質があります。

  • 与えられる文字列の長さは10000以下である。
  • 各数値は必ず1桁である。
  • 条件式は右から左に向かってグループ化される。
  • 条件部分は必ずTまたはFであり、数値が条件になることはない。
  • 式の評価結果は、必ず0〜9のいずれかの数字、T、またはFのいずれかになる。

動作例

たとえば入力が「F?1:T?4:5」の場合、出力は「4」となります。これは、まず最も右側の式「T?4:5」が解析されて4が返され、その結果として全体の式が「F?1:4」に書き換わり、条件Fは偽であるため最終的に4が出力されるからです。

アルゴリズムの考え方

この問題は、文字列を右から左へ走査しながらスタックを活用することで、シンプルかつ効率的に解くことができます。具体的な手順は以下の通りです。

  1. ret := 空文字列、n := 文字列sの長さとし、空のスタックstを用意する。
  2. i を n − 1 から 0 まで逆順にループする。
    • x := s[i] とする。
    • スタックが空でなく、かつスタックの先頭が「?」である場合は、次のように処理する。
      • 先頭の「?」をポップして取り除く。
      • first := スタックの先頭要素とし、続けて2つの要素をポップする(真の場合の値と「:」を除去)。
      • second := スタックの先頭要素とし、それをポップする。
      • x が「T」であれば first を、そうでなければ second をスタックにプッシュする。
    • 上記以外の場合は、x をそのままスタックにプッシュする。
  3. スタックが空になるまで、先頭の文字を ret の末尾に加えながらポップを繰り返す。
  4. 最後に ret を反転して返す。

C++による実装例

理解を深めるために、以下の実装コードを見てみましょう。

#include <bits/stdc++.h>
using namespace std;
class Solution {
public:
    string parseTernary(string s) {
        string ret = "";
        int n = s.size();
        stack <char> st;
        for(int i = n - 1; i >= 0; i--){
            char x = s[i];
            if(!st.empty() && st.top() == '?'){
                st.pop();
                char first = st.top();
                st.pop();
                st.pop();
                char second = st.top();
                st.pop();
                if(x == 'T'){
                    st.push(first);
                }
                else st.push(second);
            }
            else{
                st.push(x);
            }
        }
        while(!st.empty()){
            ret += st.top();
            st.pop();
        }
        reverse(ret.begin(), ret.end());
    return ret;
    }
};
main(){
    Solution ob;
    cout << (ob.parseTernary("F?1:T?4:5"));
}

入力

"F?1:T?4:5"

出力

4
  1. C++で学ぶ式ツリー(Expression Tree)の基本と具体例

    式ツリーとは何か式ツリー(Expression Tree)とは、二分木の一種であり、木の各ノードが「演算子」または「オペランド(被演算子)」のいずれかで構成される特殊なデータ構造です。数式を木構造として表現することで、コンパイラや電卓アプリなどが数式を効率的に解析・評価できるようになります。ノードの役割式ツリーにおける各ノードは、次のように役割が分かれています。葉ノード(リーフノード):オペランド(数値や変数)を表します。非葉ノード(内部ノード):演算子(+、-、*、/ など)を表します。つまり、計算の対象となる値は必ず葉に配置され、それらをどのように処理するかを示す演算子が親ノードとして上に

  2. C++で式ツリー(Expression Tree)を評価する方法|再帰を使った実装例

    本記事では、+、-、*、/ といった二項演算子から構成される式ツリー(Expression Tree)を評価し、その計算結果を返す問題について解説します。 式ツリーとは 式ツリーは二分木の一種であり、各ノードには演算子またはオペランド(被演算数)が格納されます。ノードの役割は次のように分けられます。 葉ノード:演算の対象となる値(オペランド)を保持します。 非葉ノード(内部ノード):実行すべき演算を表す二項演算子を保持します。 式ツリーを中順走査(in-order traversal)すると、元の中置記法の数式が復元できるのが特徴です。 例題で理解しよう 入力:次のような式ツリーが与えられ