数据结构-表达式树

版权声明:转载请注明出处。 https://blog.csdn.net/baidu_38304645/article/details/83180604

对于中缀表达式(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;
}

猜你喜欢

转载自blog.csdn.net/baidu_38304645/article/details/83180604
今日推荐