1. 程式人生 > >資料結構-表示式樹

資料結構-表示式樹

對於中綴表示式(e1)OP(e2),令根結點值為OP,左子樹為e1,右子樹e2,e1與e2遞迴。

如表示式:1+2*(3-4)-5/6 即 ((1) + ((2)*(3-4)))-((5)/(6))

可以形成如下的表示式樹。

先序:-+1*2-34/56 字首表示式

中序:1+2*3-4-5/6  中綴表示式

後序:1234-*+56/-  字尾表示式

其中字尾表示式可直接求值(不用考慮優先順序)。但求字尾式過程中需用優先順序,算符優先法實際在執行過程中隱含形成的邏輯結構就是一棵樹。

那麼給我們一個表示式,我們怎樣將其轉換為一個表示式樹呢?

輸入:一個表示式

輸出:各個結點的編號:左孩子編號、右孩子編號、該結點表示的字元。

首先是儲存結構定義:

//表示式樹
int lch[maxn], rch[maxn], nc;  //每個結點的左右子結點編號 結點數
char op[maxn];                 //結點的字元

演算法思想:

找到最後計算的運算子,是整顆表示式樹的根,然後遞迴。當p為0的時候考慮這個運算子,因為括號裡的運算子忽略,c1c2表示最優出現的加減號與乘除號, 如果括號外有加減號 ,肯定最後計算,如果沒有加減號,考慮乘除。如果全部沒有,說明整個表示式外面被一對括號括起來。去掉後遞迴呼叫最後運算的運算子s[c1] 它的左子樹是區間[x,c1] 右子樹是[c1+1,y]。

演算法實現:

int build_tree(char *s, int x, int y)
{
    /*找到最後計算的運算子,是整棵表示式樹的根,然後遞迴
    當p為0的時候考慮這個運算子,因為括號裡的運算子忽略。c1c2表示最優出現
    的加減號與乘除號 如果括號外有加減號,肯定最後計算,如果沒有加減號,
    考慮乘除如果全部沒有,說明整個表示式外面被一對括號括起來,去掉後遞迴
    呼叫最後運算的運算子s[c1] 它的左子樹是區間[x,c1] 右子樹是[c1+1,y] */
    int c1, c2, p, u, i;

    c1 = -1;
    c2 = -1;
    p = 0;
    if(y - x == 1) //僅一個字元 建立單獨結點
    {
        u = ++nc;
        lch[u] = 0;
        rch[u] = 0;
        op[u] = s[x];
        return u;
    }

    for(i = x; i < y; i++)
        switch(s[i])
        {
            case '(':
                p++;
                break;
            case ')':
                p--;
                break;
            case '+':
            case '-':
                if(!p)
                    c1 = i;
                break;
            case '*':
            case '/':
                if(!p)
                    c2 = i;
                break;
        }

    if(c1 < 0)                               //找不到括號外的加減號,就用乘除號
        c1 = c2;
    if(c1 < 0)
        return build_tree(s, x+1, y-1);      //整個表示式被一對括號括起來
    u = ++nc;
    lch[u] = build_tree(s, x, c1);
    rch[u] = build_tree(s, c1+1, y);
    op[u] = s[c1];

    return u;
}