感觉以前从来没有用过,突然在白书上面看见。。。。

概要   中缀表达式    后缀表达式    表达式树

一.相关概念

1.中缀表达式:

        就是熟知的表达式形式例如a+b*(c-d)-e/f,按照一定的优先级运算,不同的语言优先级不同,C语言应该是下表:

表达式总结(注pascal的运算符and和*/统计,or,xor和+-同级)

2.后缀表达式:

    后缀表达式,指的是不包含括号,运算符放在两个运算对象的后面,所有的计算按运算符出现的顺序,严格从左向右进行(不再考虑运算符的优先规则);一般我们只考虑常用二目运算符和(),例如上边的a+b*(c-d)-e/f的后缀表达式为:abcd-*+ef/-

后缀表达式的计算:
    对人脑来说不如中缀表达式好看,但是对计算机来说很有用。计算时拿一个栈来存放结果,从左往右一次扫描后缀式如果为数字(a,b,c,d,e,f)就直接加入栈中,如果为运算符(-*/-)就取出栈顶的两个元素进行运算,注意这样的运算是有顺序的,即 次栈顶 (运算) 栈顶 ,因为类似减号这样的东西是没有交换律的;

中缀表达式转后缀表达式:

    用两个栈ans,S,一个栈存后缀表达式,另一个栈维护表达式运算符优先级严格单调上升;

扫描字符 S ans
a NULL a
+ + a
b + a b
* + * a b
( + * ( a b
c + * (  a b c 
- + * ( -  a b c 
d + * ( -  a b c d
) + * () -->  +  *  a b c d -
- + *-   -->   - a b c d - * +
e -  a b c d - * + e
/ - / a b c d - * + e 
f - /  a b c d - * + e f
NULL -   --->  NULL a b c d - * + e f / -
     

 

我们从左到右扫描中缀表达式,遇到一个数字就直接加入ans,如果是运算符,先考虑运算符和S栈顶运算符的优先级,如果当前优先级小于或者等于栈顶的优先级,则弹出栈顶运算符并将其加入ans,最后再将当前的运算符加入s;特别的,当遇到’(‘时就直接加入S,遇到’)’是就将S中的最后一个’(’之后的元素依次弹出并加入ans;最后将S里面所有剩下的元素弹出并加入ans;

3.表达式树:

     表达式树就是一颗叶子结点是数,非叶子结点是运算符的二叉树(二目运算符),对于一个非叶子结点,它的左子树就代表了这个运算符左边的表达式,右子树为右边的表达式;

表达式总结可以发现这样的树的左右儿子也是有顺序的,不能随意交换。

表达式树的计算:

    对左右子树递归,再将递归结果用当前节点的运算符计算即可;所以表达式树用树形结构来替代了表达式的结构;

和中缀,后缀表达式的关系:

    中缀表达式是表达式树的中序遍历再加上某些必要的括号,后缀表达式就是表达式树的后序遍历;

    后缀表达式转表达式树,理解了表达式树的计算之后,我们只需要按照后缀表达式求值的方式建树,依旧用一个栈存字符代表的编号,每次运算符进入时退出栈顶两个元素,并接到当前运算符的左右儿子再把当前运算符标号加进去;

    中缀表达式转表达式树:

    一种出现在白书上比较简单的方法是:找整个中缀里面最后一个运算的运算符,左儿子就递归其左边的表达式,右儿子就递归其右边的表达式,但是我感觉这样子的复杂度是O(n*dep)dep为表达式树的深度。

    O(n)的我能想到的方法就是参照中缀转后缀的思想在运算符进入ans数组时直接把左右儿子接到当前运算符并弹出再加入(估计没什么用,不会卡);

二.一些应用

   1. UVA – 12219   Common Subexpression Elimination

   题意:给出一个二目表达式,中缀的形式,现在可以允许用一个数字替换第二次出现的相同表达式,求最少可以用多少个字符表示出这个表达式;

   题解:建立表达式树会直观一点,建好树之后,问题即你可以用一个数字替代前面出现的相同子树,并且会保留第一次出现的子树,这样只要贪心就好,用三元(u,l,r)表示当前节点,左子树,右子树;将每个子树都哈希一下,比较当前节点和左子树和右子树是否相同,用一个map标记是否出现;

   (直接hash一个子树的话应该也是没问题)

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<map>
 5 using namespace std;
 6 const int N=500010; 
 7 int T,vis[N],idx;
 8 char s[N],*p;
 9 struct node{
10     string s;
11     int l,r,h;
12     bool operator <(const node&A)const{
13         if(A.h!=h)return h<A.h;
14         if(A.l!=l)return l<A.l;
15         return r<A.r;
16     }
17 }v[N];
18 map<node,int>mp;
19 int solve(){
20     int now=++idx;
21     vis[now]=0;
22     node &u=v[now];
23     u.s="";u.l=u.r=u.h=0;
24     while(isalpha(*p)){
25     u.h=u.h*27+*p-'a'+1;//
26     u.s=u.s+*p;
27     p++;
28     }
29     if(*p=='('){
30         p++;u.l=solve();
31         p++;u.r=solve();
32         p++;
33     } //
34     if(mp[u]){
35         idx--;
36         return mp[u];
37     }
38     else return mp[u]=now;
39 }///
40 void print(int x){
41     if(vis[x]){printf("%d",x);return;}
42     vis[x]=1;
43     printf("%s",v[x].s.c_str());
44     if(v[x].l&&v[x].r){
45         printf("(");
46         print(v[x].l);
47         printf(",");
48         print(v[x].r);
49         printf(")");
50     }
51 }//
52 int main()
53 {    freopen("A.in","r",stdin);    
54     freopen("A.out","w",stdout);
55     scanf("%d",&T);
56     while(T--){
57         mp.clear(); 
58         scanf("%s",s+1);
59         p=s+1;idx=0;
60         int tmp=solve();
61         print(tmp);
62         printf("\n");
63     }
64     return 0;
65 }//by tkys_Austin; 
View Code

相关文章:

  • 2021-10-01
猜你喜欢
  • 2021-05-12
  • 2022-01-20
  • 2022-12-23
  • 2022-12-23
  • 2021-07-08
相关资源
相似解决方案