[PKU 2269 3295]表达式求值

{

表达式求值又是栈的应用 感觉很有用

于是找了2个问题解决了一下

在这里讲过在树上的各种栈应用

http://www.cnblogs.com/Booble/archive/2010/08/20/1804579.html

实际上对表达式进行处理本质就是对表达式树进行栈处理

}

 

我们平时使用的表达式是中缀表达式

比如:2*6-(23+7)/(1+2)=2

我们可以注意到中缀表达式具有的递归性质

S1和S2是两个合法的中缀表达式 则(S1)ch(S2)也是一个合法的中缀表达式

递归的边界即S1或S2是操作数

我们又可以用表达式树来形象地描述这个表达式


事实上 对一棵表达式树进行中序遍历即可得到中缀表达式

相应的进行前序和后序遍历可以相应的得到前缀表达式和后缀表达式

又称为波兰式和逆波兰式

(下文中简称中缀式 前缀式和后缀式)

而在计算机领域应用的更多的是后缀表达式和前缀表达式

并且在二者中后缀表达式更为常用

那么如何将一个中缀式转为后缀式呢?

 

我们可以用来实现

我们先考虑一个中缀式中会出现哪些类型的元素

有: 操作符{'+','-','*','/','(',')'}和操作数

而在表达式树中不出现括号

因表达式树有几个其他二叉树所没有的性质

  每个节点要么是叶子节点 要么有2个儿子

  分支节点就是操作符 叶子节点即为操作数

  而且 下层操作符的优先级应当高于上层操作符 (即先算下层后算上层)

括号是用来保证低级运算符的优先级的

由于第三个性质自然不需要括号出现在表达式树中

 

接下来我们通过顺序扫描(等价于中序遍历整个表达式树)和栈操作解决中缀式转后缀式的问题

当然我们还需要一个存储答案(求得的后缀式)的队列

我们在栈内存储优先级自顶向下单调递减的操作符

表现在表达式树上就是自上而下的一段路径

设栈顶元素为ch

  我们在存入ch之前就已经解决了ch的左子树S1的问题

  因为S1内的操作符必然高于ch 根据我们设计的栈的单调性 S1必然已经全部弹出

  所以我们在此之后把ch压栈

  然后根据中序遍历的顺序我们将遍历到ch的右子树S2

  继续利用压栈解决S2的问题 解决之后就会弹出ch

(下图是一个具体的例子)

具体算法如下

  首先 遇到操作数直接输出至答案序列

  因为操作数自成一个合法后缀式 相当于一个处理完毕的子树

  而我们每读到一个'('应当压栈

  相应的我们读到一个')'就弹栈 直到遇到'('

  (除括号外弹出元素进入答案序列,括号也需弹出) 括号不入栈

  读到一个非括号操作符ch 弹栈直到栈顶元素优先级低于ch或为'('或栈空 最后压入ch

  当扫描完毕时将栈内所有元素弹出 输出至答案序列

贴出中缀式转后缀式代码

 

1 const maxn=1000;
2 pri:array['('..'/']of longint=(0,3,2,1,0,1,0,2);
3 let:set of char=['A'..'Z'];
4  var ans,stack:array[1..maxn]of char;
5 top,tt,i:longint;
6 ch:char;
7  begin
8 assign(input,'exp.in'); reset(input);
9 assign(output,'exp.out'); rewrite(output);
10 top:=0; tt:=0;
11 fillchar(stack,sizeof(stack),0);
12  while not eoln do
13 begin
14 read(ch);
15 if ch in let
16 then begin
17 inc(tt);
18 ans[tt]:=ch;
19 end
20 else if ch='('
21 then begin
22 inc(top);
23 stack[top]:=ch;
24 end
25 else if ch=')'
26 then begin
27 while stack[top]<>'(' do
28 begin
29 inc(tt);
30 ans[tt]:=stack[top];
31 dec(top);
32 end;
33 dec(top);
34 if top<0
35 then begin
36 writeln('Error while working.');
37 close(input); close(output);
38 halt;
39 end;
40 end
41 else begin
42 while (top>0)and(pri[stack[top]]>=pri[ch]) do
43 begin
44 inc(tt);
45 ans[tt]:=stack[top];
46 dec(top);
47 end;
48 inc(top);
49 stack[top]:=ch;
50 end;
51 end;
52  while top>0 do
53 begin
54 inc(tt);
55 ans[tt]:=stack[top];
56 dec(top);
57 end;
58  for i:=1 to tt do
59 write(ans[i]);
60 writeln;
61 close(input); close(output);
62  end.
63  

得到了后缀式 我们便能方便地计算表达式的值

 

根据后缀式计算表达式的值很简单

也是利用栈

扫描整个后缀式

碰到操作数就压栈 碰到操作符就弹出两个数运算 再把结果压栈

扫描完毕 栈中有且仅有一个元素 就是结果

贴出代码

 

1 const c:array[1..6]of char=('(',')','+','-','*','/');
2 c0:set of char=['(',')','+','-','*','/'];
3 n0:set of char=['0'..'9'];
4 pri:array['('..'/']of longint=(0,3,2,1,0,1,0,2);
5 id:array['('..'/']of longint=(1,2,5,3,0,4,0,6);
6 maxn=100;
7  var tab,flag,data:array[1..maxn]of longint;
8 ans,stack:array[1..maxn]of record x,y:longint; end;
9 t,t1,tt,last,i,top:longint;
10 key:boolean;
11 ch:char;
12  begin
13 assign(input,'cal.in'); reset(input);
14 assign(output,'cal.out'); rewrite(output);
15 t:=0; t1:=0; last:=0; key:=false;
16 fillchar(data,sizeof(data),0);
17 fillchar(tab,sizeof(tab),0);
18 fillchar(flag,sizeof(flag),0);
19  while not eoln do
20 begin
21 read(ch);
22 if ch in c0
23 then begin
24 if key
25 then begin
26 inc(t1);
27 data[t1]:=last;
28 inc(t);
29 tab[t]:=t1;
30 flag[t]:=1;
31 last:=0;
32 key:=false;
33 end;
34 inc(t);
35 tab[t]:=id[ch];
36 flag[t]:=2;
37 end
38 else begin
39 last:=last*10+ord(ch)-48;
40 if not key then key:=true;
41 end;
42 end;
43  if key
44 then begin
45 inc(t1);
46 data[t1]:=last;
47 inc(t);
48 tab[t]:=t1;
49 flag[t]:=1;
50 last:=0;
51 key:=false;
52 end;
53 top:=0; tt:=0;
54  for i:=1 to t do
55 begin
56 if flag[i]=1
57 then begin
58 inc(tt);
59 ans[tt].x:=tab[i];
60 ans[tt].y:=flag[i];
61 end
62 else if (flag[i]=2)and(tab[i]=1)
63 then begin
64 inc(top);
65 stack[top].x:=tab[i];
66 stack[top].y:=flag[i];
67 end
68 else if (flag[i]=2)and(tab[i]=2)
69 then begin
70 while (top>0)and((stack[top].x<>1)or(stack[top].y<>2)) do
71 begin
72 inc(tt);
73 ans[tt].x:=stack[top].x;
74 ans[tt].y:=stack[top].y;
75 dec(top);
76 end;
77 dec(top);
78 end
79 else begin
80 while (top>0)and(pri[c[stack[top].x]]>=pri[c[tab[i]]]) do
81 begin
82 inc(tt);
83 ans[tt].x:=stack[top].x;
84 ans[tt].y:=stack[top].y;
85 dec(top);
86 end;
87 inc(top);
88 stack[top].x:=tab[i];
89 stack[top].y:=flag[i];
90 end;
91 end;
92  while top>0 do
93 begin
94 inc(tt);
95 ans[tt].x:=stack[top].x;
96 ans[tt].y:=stack[top].y;
97 dec(top);
98 end;
99 top:=0;
100  for i:=1 to tt do
101 begin
102 if ans[i].y=2
103 then begin
104 case ans[i].x of
105 3:stack[top-1].x:=stack[top-1].x+stack[top].x;
106 4:stack[top-1].x:=stack[top-1].x-stack[top].x;
107 5:stack[top-1].x:=stack[top-1].x*stack[top].x;
108 6:stack[top-1].x:=stack[top-1].x div stack[top].x;
109 end;
110 dec(top);
111 end
112 else begin
113 inc(top);
114 stack[top].x:=data[ans[i].x];
115 end;
116 end;
117 writeln(stack[1].x);
118 close(input); close(output);
119  end.
120  

由于生成具体数据比较复杂

 

把生成数据的程序也给出来

实际上是借用了以前生成随机二叉树的程序

生成一棵表达式树 能够生成数据+运算结果

 

1 const maxn=1000;
2  var t,tt,nx,ns,y,top,n,x,i:longint;
3 c:array[1..4]of char;
4 key,h,l,r:array[1..maxn]of longint;
5 ch:array[1..maxn]of char;
6 stack:array[1..maxn]of record x,s:longint end;
7  begin
8 randomize;
9 assign(input,'input.txt'); reset(input);
10 assign(output,'exp.in'); rewrite(output);
11 readln(n);
12 n:=n div 2;
13 n:=2*n+1;
14 close(input);
15 t:=0; tt:=1;
16 c[1]:='+'; c[2]:='*'; c[3]:='-'; c[4]:='/';
17 top:=1; stack[1].x:=1; stack[1].s:=n;
18  while top>0 do
19 begin
20 nx:=stack[top].x;
21 ns:=stack[top].s;
22 dec(top);
23 if ns<>1
24 then ch[nx]:=c[random(4)+1]
25 else begin
26 inc(t);
27 ch[nx]:=chr(t+64);
28 continue;
29 end;
30 y:=random(ns div 2-1)*2+1;
31 if y>0
32 then begin
33 inc(tt); l[nx]:=tt;
34 if key[nx]<0 then key[tt]:=key[nx]-1
35 else key[tt]:=-1;
36 inc(top); stack[top].x:=tt; stack[top].s:=y;
37 end;
38 if ns-y-1>0
39 then begin
40 inc(tt); r[nx]:=tt;
41 if key[nx]>0 then key[tt]:=key[nx]+1
42 else key[tt]:=1;
43 inc(top); stack[top].x:=tt; stack[top].s:=ns-y-1;
44 end;
45 end;
46 top:=1; stack[top].x:=1;
47 fillchar(h,sizeof(h),0);
48  while top>0 do
49 begin
50 x:=stack[top].x;
51 if (l[x]<>0)and(h[l[x]]=0)
52 then begin
53 inc(top);
54 stack[top].x:=l[x];
55 h[l[x]]:=1;
56 end
57 else begin
58 if (l[x]=0)and(key[x]<0)
59 then for i:=1 to abs(key[x]) do write('(');
60 write(ch[x]);
61 dec(top);
62 if (r[x]=0)and(key[x]>0)
63 then for i:=1 to key[x] do write(')');
64 if (r[x]<>0)and(h[r[x]]=0)
65 then begin
66 inc(top);
67 stack[top].x:=r[x];
68 h[r[x]]:=1;
69 end;
70 end;
71 end;
72 writeln; close(output);
73 assign(output,'exp0.out'); rewrite(output);
74 top:=1; stack[top].x:=1;
75 fillchar(h,sizeof(h),0);
76  while top>0 do
77 begin
78 x:=stack[top].x;
79 if (l[x]<>0)and(h[l[x]]=0)
80 then begin
81 inc(top);
82 stack[top].x:=l[x];
83 h[l[x]]:=1;
84 end
85 else if (r[x]<>0)and(h[r[x]]=0)
86 then begin
87 inc(top);
88 stack[top].x:=r[x];
89 h[r[x]]:=1;
90 end
91 else begin
92 write(ch[x]);
93 dec(top);
94 end;
95 end;
96 writeln;
97 close(output);
98  end.
99  

还有2个问题

 

分别是pku 2269 和 pku3295

其中pku2269用集合代替了操作数 注意细节

pku3295是前缀式求值

我的做法把操作数操作符一起存了

每次就试探着看栈顶几个元素可不可以放在一起算 可以算就算了压栈

直到不能算位置 继续压入新元素

贴代码

 

Tau
1 const n0:set of char=['p','q','r','s','t'];
2 c0:set of char=['K','A','N','C','E'];
3 c1:array[2..6]of char=('K','A','N','C','E');
4 c:array['A'..'N']of longint=(3,0,5,0,6,0,0,0,0,0,2,0,0,4);
5 maxn=100;
6  var n:array['p'..'t']of longint;
7 stack:array[1..maxn]of longint;
8 data:array[1..maxn]of char;
9 flag:boolean;
10 m,i:longint;
11  function check:boolean;
12  var top,i:longint;
13 ch:char;
14 key:boolean;
15  begin
16 top:=0;
17 fillchar(stack,sizeof(stack),0);
18  for i:=1 to m do
19 begin
20 ch:=data[i];
21 if ch='0'
22 then begin
23 close(input); close(output);
24 halt;
25 end;
26 inc(top);
27 if ch in c0
28 then stack[top]:=c[ch]
29 else stack[top]:=n[ch];
30 key:=true;
31 while key do
32 begin
33 if (top>=2)and(stack[top-1]=4)and(stack[top]<2)
34 then begin
35 stack[top-1]:=not stack[top];
36 dec(top);
37 continue;
38 end;
39 if (top>=3)and(stack[top-2]=2)and(stack[top]<2)and(stack[top-1]<2)
40 then begin
41 stack[top-2]:=stack[top] and stack[top-1];
42 dec(top,2);
43 continue;
44 end;
45 if (top>=3)and(stack[top-2]=3)and(stack[top]<2)and(stack[top-1]<2)
46 then begin
47 stack[top-2]:=stack[top] or stack[top-1];
48 dec(top,2);
49 continue;
50 end;
51 if (top>=3)and(stack[top-2]=5)and(stack[top]<2)and(stack[top-1]<2)
52 then begin
53 stack[top-2]:=((stack[top-1] shl stack[top]) xor 1) and 1;
54 dec(top,2);
55 continue;
56 end;
57 if (top>=3)and(stack[top-2]=6)and(stack[top]<2)and(stack[top-1]<2)
58 then begin
59 stack[top-2]:=(stack[top] xor stack[top-1])xor 1;
60 dec(top,2);
61 continue;
62 end;
63 key:=false;
64 end;
65 end;
66  if stack[1]<>1
67 then check:=false
68 else check:=true;
69  end;
70  procedure DFS(dep:char);
71  var i:longint;
72  begin
73  if dep>'t'
74 then flag:=flag and check
75 else for i:=0 to 1 do
76 begin
77 n[dep]:=i;
78 dfs(chr(ord(dep)+1));
79 end;
80  end;
81 begin
82 assign(input,'tau.in'); reset(input);
83 assign(output,'tau.out'); rewrite(output);
84 while not eof do
85 begin
86 flag:=true;
87 i:=0;
88 while not eoln do
89 begin
90 inc(i);
91 read(data[i]);
92 end;
93 m:=i;
94 DFS('p');
95 if flag
96 then writeln('tautology')
97 else writeln('not');
98 readln;
99 end;
100 close(input); close(output);
101 end.
102
Friends
1 const maxl=256;
2 maxn=256;
3 pri:array['('..'/']of longint=(0,3,2,1,0,1,0,2);
4 type node=
5 record
6 c:array[1..maxl]of char;
7 n:longint;
8 end;
9 var ans,cals{stack}:array[1..maxn]of node;
10 c,stack:array[1..maxn]of char;
11 h:array['A'..'Z']of longint;
12 t,top,i,j:longint;
13 ch:char;
14 begin
15 assign(input,'friend.in'); reset(input);
16 assign(output,'friend.out'); rewrite(output);
17 while not eof do
18 begin
19 t:=0;
20 top:=0;
21 while not eoln do
22 begin
23 read(ch);
24 if ch='{'
25 then begin
26 i:=0;
27 while ch<>'}' do
28 begin
29 if i>0 then c[i]:=ch;
30 inc(i);
31 read(ch);
32 end;
33 inc(t);
34 move(c,ans[t].c,sizeof(c));
35 ans[t].n:=i-1;
36 end
37 else if ch='('
38 then begin
39 inc(top);
40 stack[top]:='(';
41 end
42 else if ch=')'
43 then begin
44 while stack[top]<>'(' do
45 begin
46 inc(t);
47 ans[t].n:=-1;
48 ans[t].c[1]:=stack[top];
49 dec(top);
50 end;
51 dec(top);
52 end
53 else begin
54 while (top>0)and(pri[stack[top]]>=pri[ch]) do
55 begin
56 inc(t);
57 ans[t].n:=-1;
58 ans[t].c[1]:=stack[top];
59 dec(top);
60 end;
61 inc(top);
62 stack[top]:=ch;
63 end;
64 end;
65 while top>0 do
66 begin
67 inc(t);
68 ans[t].n:=-1;
69 ans[t].c[1]:=stack[top];
70 dec(top);
71 end;
72 top:=0;
73 for i:=1 to t do
74 begin
75 if ans[i].n=-1
76 then case ans[i].c[1] of
77 '+': begin
78 fillchar(h,sizeof(h),0);
79 for j:=1 to cals[top].n do
80 inc(h[cals[top].c[j]]);
81 for j:=1 to cals[top-1].n do
82 inc(h[cals[top-1].c[j]]);
83 dec(top);
84 cals[top].n:=0;
85 for ch:='A' to 'Z' do
86 if h[ch]>0
87 then begin
88 inc(cals[top].n);
89 cals[top].c[cals[top].n]:=ch;
90 end;
91 end;
92 '-': begin
93 fillchar(h,sizeof(h),0);
94 for j:=1 to cals[top].n do
95 dec(h[cals[top].c[j]]);
96 for j:=1 to cals[top-1].n do
97 inc(h[cals[top-1].c[j]]);
98 dec(top);
99 cals[top].n:=0;
100 for ch:='A' to 'Z' do
101 if h[ch]>0
102 then begin
103 inc(cals[top].n);
104 cals[top].c[cals[top].n]:=ch;
105 end;
106 end;
107 '*': begin
108 fillchar(h,sizeof(h),0);
109 for j:=1 to cals[top].n do
110 inc(h[cals[top].c[j]]);
111 for j:=1 to cals[top-1].n do
112 inc(h[cals[top-1].c[j]]);
113 dec(top);
114 cals[top].n:=0;
115 for ch:='A' to 'Z' do
116 if h[ch]=2
117 then begin
118 inc(cals[top].n);
119 cals[top].c[cals[top].n]:=ch;
120 end;
121 end;
122 end
123 else begin
124 inc(top);
125 move(ans[i].c,cals[top].c,sizeof(ans[i].c));
126 cals[top].n:=ans[i].n;
127 end;
128 end;
129 write('{');
130 fillchar(h,sizeof(h),0);
131 for i:=1 to cals[1].n do
132 inc(h[cals[1].c[i]]);
133 for ch:='A' to 'Z' do
134 if h[ch]>0 then write(ch);
135 writeln('}');
136 readln;
137 end;
138 close(input); close(output);
139 end.
140

最后注意转表达式时

 

>=和>是有质的区别的

关系到同一优先级的运算符运算次序

 

BOB HAN原创 转载请注明出处

posted on 2010-08-31 22:41  Master_Chivu  阅读(1874)  评论(0编辑  收藏  举报

导航