スタックとバイナリツリー-式・式ツリー・式の評価

合計制限時間:1000ms

メモリ制限:65535kB

説明

ご存知のように、どの式も式ツリーで表すことができます。たとえば、式a + b * cは、次の式ツリーとして表すことができます。

   +
  / \
a *
    / \
    bc

ここで、中置式を指定します。この中置式は、変数(数値なし)で表されます。この中置式は、式の二分木の形式で出力してください。

入る

入力は3つの部分に分かれています。
最初の部分は行、つまり中置式です(長さは50以下です)。中置式には、変数(az)を表す小文字を含めることができます。また、数字やスペースを含まない演算子(+、-、*、/、括弧)を含めることもできます。
2番目の部分は整数n(n <10)で、中置式の変数の数を表します。
3番目の部分にはn行あり、各行の形式はC x、Cは変数の文字、xは変数の値です。

出力

出力は3つの部分に分割されます。最初の部分は、式の逆ポーランド式式です。これは、式ツリーの後根をトラバースした結果です。1行を占めます。
2番目の部分は、サンプル出力に示されている式ツリーの表示です。二分木が完全な二分木である場合、一番下のリーフノードはそれぞれ横座標の1、3、5、7 ...の位置を占め(左端の座標は1)、次にそれらの親ノード横座標は中央にあります2つの子ノードの。二分木がいっぱいでない場合は、ノードがない場所にスペースを入力します(ただし、行末のスペースはすべて省略してください)。親ノードと子ノードの各行は1行で区切られ、スラッシュ(/)と円記号(\)はツリーの関係を示すために使用されます。/の横座標の位置は、親ノードの横座標の左側の1つの正方形であり、表示される横座標の位置は、親ノードの横座標の右側の1つの正方形です。つまり、ツリーの高さがmの場合、出力は2m-1行になります。
3番目の部分は整数であり、値を変数に代入した後の中置式の値を表します。注意すべき点の1つは、除算は算術演算を表すことです。つまり、小数点以下の部分は破棄されます。同時に、テストデータはゼロによる除算がないことを保証します。

サンプル入力

a+b*c
3
a 2
b 7
c 5

サンプル出力

abc*+
   +
  / \
 a   *
    / \
    b c
37
#include <iostream>
#include <cstring>
#include <algorithm>
#include <stack>
#include <map>
#include <vector>
using namespace std;

map<char,int> priority = {
   
   {'+', 1}, {'-', 1}, {'*', 2}, {'/', 2}, {'(', 0}};
map<char,int> value;

struct node_t {
    char val;
    node_t *left;
    node_t *right;
    node_t(char val_, node_t *left_ = NULL, node_t *right_ = NULL) : val(val_), left(left_), right(right_) {}
};

stack<char> op;
stack<node_t*> expression;
inline void doit()
{
    node_t *b = expression.top(); expression.pop();
    node_t *a = expression.top(); expression.pop();
    node_t *c = new node_t(op.top(), a, b); op.pop();
    expression.push(c);
}
node_t *build_tree(char *in) {
    int l = strlen(in);
    for (int i = 0; i < l; ++i) {
        if (isalpha(in[i])) {
            expression.push(new node_t(in[i]));
        }
        else {
            if (in[i] == '(')
                op.push(in[i]);
            else if (in[i] == ')') {
                while (op.top() != '(')
                    doit();
                op.pop(); // for '('
            }
            else {
                while (!op.empty() && priority[op.top()] >= priority[in[i]])
                    doit();
                op.push(in[i]);
            }
        }
    }
    while (!op.empty()) {
        doit();
    }
    return expression.top();
}

void postfix_dfs(node_t *cur){
    if (cur->left)
        postfix_dfs(cur->left);
    if (cur->right)
        postfix_dfs(cur->right);
    putchar(cur->val);
}

int cal(int a, int b, char o)
{
    if (o == '+') return a+b;
    if (o == '-') return a-b;
    if (o == '*') return a*b;
    if (o == '/') return a/b;
    cerr << "bad o" << endl;
    return 0;
}

int cal_tree(node_t* cur){
    if (isalpha(cur->val))
        return value[cur->val];
    return cal(cal_tree(cur->left), cal_tree(cur->right), cur->val);
}

int tree_height(node_t *cur)
{
    if (isalpha(cur->val))
        return 1;
    return 1+max(tree_height(cur->left), tree_height(cur->right));
}

void print_tree(node_t *rt)
{
    struct Node{
        node_t *node;
        int pos;
    };

    int tree_h = tree_height(rt);

    vector<Node> *v1 = new vector<Node>(), *v2 = new vector<Node>();
    v1->push_back({rt, (1<<(tree_h-1))-1});
    for (int h = tree_h; h >= 1; --h) {
        int last_pos = 0;
        int bias = 1<<(h-2);

        /* print node value */
        for (Node nd : *v1) {
            for (int i = last_pos; i < nd.pos; ++i)
                putchar(' ');
            putchar(nd.node->val);
            last_pos = nd.pos+1;
            if (h > 1 && !isalpha(nd.node->val)) {
                v2->push_back({nd.node->left, nd.pos - bias});
                v2->push_back({nd.node->right, nd.pos + bias});
            }
        }
        putchar('\n');

        if (h == 1)
            break;

        /* print branch */
        last_pos = 0;
        for (Node nd : *v1) {
            if (isalpha(nd.node->val))
                continue;
            for (int i = last_pos; i < nd.pos-1; ++i)
                putchar(' ');
            printf("/ \\");
            last_pos = nd.pos + 2;
        }
        putchar('\n');

        /* get ready for next loop */
        v1->clear();
        swap(v1, v2);
    }

}

int main()
{
    char in[55];
    cin >> in;

    node_t *rt = build_tree(in);

    postfix_dfs(rt);
    printf("\n");

    print_tree(rt);

    int n; cin >> n;
    for (int i = 0; i < n; ++i) {
        char c; int v;
        cin >> c >> v;
        value[c] = v;
    }
    cout << cal_tree(rt) << endl;

    system("pause");
    return 0;
}

【分析】

  1. 「中置式を直接見つける」という考えを借りて、中置式を使用して式ツリーを直接構築することもできます
  2. 違いは、中置式を直接求める場合、スタックの一番上にある2つの数値の演算結果をスタックに戻すことです。今回は、スタックの一番上の2つのノードによって形成された新しいノードをスタックに戻します。スタック。
  3. データサイズが大きすぎるため、配列を開くことができず、再帰印刷にdfsを使用できません。代わりに、bfs印刷が使用されます。
  4. last_posマークが付いた中央のスペースを印刷するのに適した方法です。
  5. 階層型bfsメソッド:キューはキュー構造ではなくベクトル構造を使用し、深度情報はノード情報に格納されません。2つのベクトルポインターを使用すると、スワップはサイクルの最後に書き込むための便利な方法です。

おすすめ

転載: blog.csdn.net/w112348/article/details/109406854