[luogu1175] 表达式的转换(递归)

题目
转了一圈发现都是用栈的,没人用表达式树递归做吗…个人感觉这种做法更好理解
不知道表达式树的,可以先看这篇博文

例如图片中这棵表达式树对应的就是 4 + 1 ( 5 2 ) 6 / 3 (来源见水印)

大致思路就是,对于表达式的一段子串[L,r],找出这段区间中最晚被计算的运算符c[mid],然后以mid为根,递归处理[L,mid-1]和[mid+1,r]。不过代码实现中并不需要真正把这棵树建出来。因为后缀表达式本质上就是表达式树的后序遍历,所以只要先将左子树处理成后缀表达式,再处理右子树,最后把根c[mid]放在后缀表达式的尾部就行了。

由于我的代码是从另一道计算表达式修改而来,所以有些地方可能比较冗余。
代码中有详细注释。

#include<bits/stdc++.h>
using namespace std;
const int N=1001;
char c[N];
int s[N],b[N],len;   //s中存放的是后缀表达式;len为长度;b[i]表示s[i]是数还是符号,数就是0,符号就是1

int isc(int x){ return c[x]=='+'||c[x]=='-'||c[x]=='*'||c[x]=='/'||c[x]=='^'; }   //判断c[x]是不是符号

int js(int a,int b,char x){  //计算
    if (x=='+') return a+b;
    if (x=='-') return a-b;
    if (x=='*') return a*b;
    if (x=='/') return a/b;
    if (x=='^') return pow(a,b);
}

int prio(char x){   //优先级
    if (x=='+'||x=='-') return 1;
    if (x=='*'||x=='/') return 2;
    if (x=='^') return 3;
    return 4;
}

int cnum(int L){    //返回位置L的数
    return c[L]-'0';
}

void cal(int L,int r){   //递归到[L,r]区间
    int mid=L,cnt=0,flag=0;    //mid找最后运算的字符位置,cnt是统计括号的,flag标记这一段里有没有运算符
    if (c[L]=='('){    //下面这一段代码判断当前这一段是不是被一对括号包着
        int i,cnt=1;
        for(i=L+1;i<=r;i++){
            if (cnt==0) break;
            if (c[i]=='(') cnt++;
            if (c[i]==')') cnt--;
        }
        if (i>r) { cal(L+1,r-1);return; }   //如果是的话直接去掉括号
    }
    for(int i=L;i<=r;i++){
        if (c[i]=='(') cnt++;
        if (c[i]==')') cnt--;
        if (isc(i)){
            flag=1;
            if (cnt==0&&prio(c[i])<=prio(c[mid])) mid=i;   //在括号外且优先级较低
        }
    }
    if (!flag){   //如果当前这一段只有数字
        s[++len]=cnum(L);   //直接加入后缀表达式
        return;
    }
    cal(L,mid-1);cal(mid+1,r);   //递归左右子树
    s[++len]=c[mid];b[len]=1;    //加入后缀表达式
}

void print(){    //这一段就是计算后缀表达式
    while(len>1){
        for(int i=1;i<=len;i++)
         if (b[i]) printf("%c ",s[i]);
          else printf("%d ",s[i]);
        int mid;
        for(mid=1;mid<=len;mid++)
         if (b[mid]) break;
        s[mid-2]=js(s[mid-2],s[mid-1],s[mid]);
        for(int i=mid-1;i<=len-2;i++) s[i]=s[i+2],b[i]=b[i+2];
        len-=2;
        printf("\n");
    }
    printf("%d",s[1]);
}

int main(){
    scanf("%s",c);
    int n=strlen(c);
    cal(0,n-1);
    print();
    return 0;
}

猜你喜欢

转载自blog.csdn.net/ymzqwq/article/details/81013745