1. 程式人生 > >表達式樹

表達式樹

root 葉子 處理 head continue calc header 表達 方便

1. 筆記
表達式樹是一種存儲和計算表達式的方式。表達式樹的葉子結點均為數,非葉子結點均為運算符。我自己摸索了一下用表達式樹處理表達式,確實很直觀方便。下面的代碼可以處理+,-,*,/,%,^六種左結合的二元運算,優先級為:

運算符 優先級
+,- 3
*,/,% 2
^ 1
其它 0

2. 代碼

/*
備註:
未嚴格測試,可能有bug
2018/09/09
*/
#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define ms(arr,a) memset(arr,a,sizeof arr)
#define debug(x) cout<<"< "#x" = "<<x<<" >"<<endl
int pri[300];
void init_pri()
{
    pri[‘+‘]=pri[‘-‘]=3;
    pri[‘*‘]=pri[‘/‘]=pri[‘%‘]=2;
    pri[‘^‘]=1;
}
struct node
{
    double v;
    char c;
    node *fa,*l,*r;
    node(){c=v=0;fa=l=r=NULL;}
    node(double x){v=x;c=0;fa=l=r=NULL;}
    node(char x){v=0;c=x;fa=l=r=NULL;}
};
void recycle(node *root)
{
    if(root==NULL)return;
    recycle(root->l);recycle(root->r);
    delete root;
}

const int maxn=1e3;
char s[maxn];
const double eps=1e-10;
inline bool is_num(char *i)
{
    return ((*i)>=‘0‘&&(*i)<=‘9‘)||(*i)==‘.‘;
}
double get_num(char *&i)
{
    bool is_f=false;double it=0.1;
    double ret=0;
    for(;is_num(i);++i)
    {
        if((*i)==‘.‘){is_f=true;continue;}
        if(is_f)
        {
            ret=ret+((*i)-‘0‘)*it;
            it=it/10;
        }else ret=ret*10+(*i)-‘0‘;
    }
    i--;
    return ret;
}
double calc(node *root)
{
    if(root->c==0)return root->v;
    double lft=calc(root->l),rgt=calc(root->r);
    switch(root->c)
    {
    case ‘+‘:
        return lft+rgt;
        break;
    case ‘-‘:
        return lft-rgt;
        break;
    case ‘*‘:
        return lft*rgt;
        break;
    case ‘/‘:
        return lft/rgt;
        break;
    case ‘%‘:
        return int(lft)%int(rgt);
        break;
    case ‘^‘:
        return pow(lft,rgt);
        break;
    }
}
node* construct(char *l,char *r)
{
    node *pos=NULL,*nxt,*root;
    for(char *i=l;i<=r;++i)
    {
        //構造新結點
        if((*i)==‘(‘)
        {
            char *lft=i+1;
            int cnt=1;
            while(cnt)
            {
                i++;
                if((*i)==‘(‘)cnt++;
                if((*i)==‘)‘)cnt--;
            }
            nxt=construct(lft,i-1);
            double tmp=calc(nxt);
            recycle(nxt);
            nxt=new node(tmp);
        }
        else if(is_num(i))nxt=new node(get_num(i));
        else nxt=new node((*i));
        //插入新結點
        node *a=pos,*b=NULL;
        pos=nxt;
        if(a==NULL){root=nxt;continue;}
        while(a&&pri[a->c]<=pri[nxt->c]){b=a;a=a->fa;}
        if(a==NULL){root=nxt;nxt->l=b;b->fa=nxt;continue;}
        if(b==NULL){a->r=nxt;nxt->fa=a;continue;}
        if(b==a->l)a->l=nxt;
        else a->r=nxt;
        nxt->fa=a;nxt->l=b;b->fa=nxt;
    }
    return root;
}
int main()
{
    init_pri();
    printf(">");
    while(~scanf("%s",s))
    {
        node *root=construct(s,s+strlen(s)-1);
        double ans=calc(root);
        long long nans=(long long)ans;
        if((ans-nans<eps)&&(ans-nans>-eps))printf("%lld",nans);
        else printf("%.6f",ans);
        printf("\n\n>");
        recycle(root);
    }
}

表達式樹