表达式求值
注意:这是一篇个人学习笔记,如果有人因为某些原因点了进来并且要看一下,请一定谨慎地阅读,因为可能存在各种奇怪的错误,如果有人发现错误请指出谢谢!
以前的:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<cstdio> 2 #include<cstring> 3 #include<cmath> 4 using namespace std; 5 int lc[10000],rc[10000]; 6 int type[10000]; 7 double data[10000]; 8 char s[10000]; 9 int nc,len,p; 10 bool judge_num(int x,int y) 11 { 12 if(y-x==1&&s[x]=='-') return false; 13 if(s[x]=='+'||s[x]=='*'||s[x]=='/'||s[x]=='^') 14 return false; 15 for(int i=x+1;i<y;i++) 16 { 17 if(s[i]=='+'||s[i]=='-'||s[i]=='*'||s[i]=='/'||s[i]=='^') 18 return false; 19 } 20 return true; 21 } 22 int build(int x,int y) 23 { 24 int i,c1=-1,c2=-1,c3=-1,p=0; 25 int u; 26 if(judge_num(x,y)==true) 27 { 28 u=++nc; 29 lc[u]=rc[u]=0; 30 type[u]=0; 31 sscanf(s+x,"%lf",&data[u]); 32 return u; 33 } 34 for(i=x;i<y;i++) 35 { 36 switch(s[i]) 37 { 38 case '(': p++;break; 39 case ')': p--;break; 40 case '+': case '-': if(!p) c1=i;break; 41 case '*': case '/': if(!p) c2=i;break; 42 case '^': if(!p) c3=i;break; 43 } 44 } 45 if(c1<0) c1=c2; 46 if(c1<0) c1=c3; 47 if(c1<0) return build(x+1,y-1); 48 u=++nc; 49 lc[u]=build(x,c1); 50 rc[u]=build(c1+1,y); 51 if(s[c1]=='+') type[u]=1; 52 else if(s[c1]=='-') type[u]=2; 53 else if(s[c1]=='*') type[u]=3; 54 else if(s[c1]=='/') type[u]=4; 55 else type[u]=5; 56 return u; 57 } 58 double run(int u) 59 { 60 if(type[u]==1) return run(lc[u])+run(rc[u]); 61 if(type[u]==2) return run(lc[u])-run(rc[u]); 62 if(type[u]==3) return run(lc[u])*run(rc[u]); 63 if(type[u]==4) return run(lc[u])/run(rc[u]); 64 if(type[u]==5) return pow(run(lc[u]),run(rc[u])); 65 return data[u]; 66 } 67 int main() 68 { 69 scanf("%s",s+1); 70 len=strlen(s+1); 71 p=build(1,len+1); 72 printf("%.3lf",run(p)); 73 return 0; 74 }
写了个O(n)的表达式树...实际要用可能要稍微改一下
题面:http://210.33.19.103/contest/997
中缀转后缀自然是不用的...
这里大部分的写法跟网上是一样的(就是两个栈:操作符栈,操作数栈;遇到数就加入数栈,遇到符号就while(栈顶操作符优先级>=当前的)不断弹出栈顶操作符(弹出方法:弹出操作符,以及两个栈顶操作数,做完运算后将结果放回操作数栈)),然而写的比较麻烦..写了一个"栈套栈",遇到左括号就新建一层栈,遇到右括号就做完当前层栈留下的运算符,将栈的层数减1,并把剩下的唯一一个数放入上一层栈
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 //#pragma GCC optimize(3) 2 #include<cstdio> 3 #include<algorithm> 4 #include<cstring> 5 #include<vector> 6 using namespace std; 7 #define fi first 8 #define se second 9 #define mp make_pair 10 #define pb push_back 11 typedef long long ll; 12 typedef unsigned long long ull; 13 14 int n,md; 15 char ss[5001000]; 16 17 void do_ub(int x) 18 { 19 if(!x) 20 { 21 printf("failed:%d\n",x); 22 int *a=0;*a=234; 23 } 24 } 25 #define assert(x) do_ub(x) 26 27 struct Nd 28 { 29 int d; 30 int type;//0:数字;1:+;2:-;3:*;4:/;5:(;6:) 31 int num; 32 }; 33 Nd pre[5001000]; 34 int inv[500100]; 35 int left,plen; 36 int order[]={3,1,1,2,2}; 37 bool isdigit1(char x){return x>='0'&&x<='9';} 38 int ma[666]; 39 40 int an[5001000]; 41 struct TNd 42 { 43 int ch[2]; 44 int type; 45 int d,num; 46 }nn[5001000]; 47 int mem; 48 struct ST 49 { 50 int st1[10001000],st2[10001000],tp1,tp2; 51 ST() 52 { 53 tp1=0;tp2=1;st2[1]=0; 54 } 55 void push(int x) 56 { 57 st1[++tp1]=x; 58 } 59 bool empty() 60 { 61 assert(tp1>=st2[tp2]); 62 return tp1==st2[tp2]; 63 } 64 void pop() 65 { 66 assert(tp1>st2[tp2]); 67 if(tp1>st2[tp2]) --tp1; 68 } 69 int top() 70 { 71 assert(tp1>st2[tp2]); 72 return st1[tp1]; 73 //return tp1>st2[tp2]?st1[tp1]:0; 74 } 75 void add_stack() 76 { 77 st2[++tp2]=tp1; 78 } 79 void del_stack() 80 { 81 assert(tp1==st2[tp2]); 82 --tp2; 83 } 84 }st1,st2; 85 int calc(int a,int b,int c) 86 { 87 if(a==-1||b==-1) return -1; 88 switch(c) 89 { 90 case 1: 91 return (a+b)%md; 92 case 2: 93 return (a-b+md)%md; 94 case 3: 95 return ll(a)*b%md; 96 case 4: 97 if(b==0) return -1; 98 return ll(a)*inv[b]%md; 99 default: 100 assert(0); 101 return 0; 102 } 103 } 104 void pop1() 105 { 106 int t1,t2,t3,t; 107 t3=st2.top();st2.pop(); 108 t2=st1.top();st1.pop(); 109 if(st1.empty()) 110 { 111 assert(t3==1||t3==2); 112 t1=0; 113 } 114 else 115 { 116 t1=st1.top();st1.pop(); 117 } 118 t=++mem; 119 nn[t].type=t3; 120 nn[t].d=calc(nn[t1].d,nn[t2].d,t3); 121 nn[t].ch[0]=t1;nn[t].ch[1]=t2; 122 st1.push(t); 123 } 124 int len; 125 int calc_r1(int a,int b,int c)//找出x使得a c x = b 126 { 127 if(a==-2||b==-2) return -2; 128 if(a==-1||b==-1) return -1; 129 switch(c) 130 { 131 case 1: 132 return calc(b,a,2); 133 case 2: 134 return calc(a,b,2); 135 case 3: 136 if(a==0) return b==0?-1:-2; 137 return calc(b,a,4); 138 case 4: 139 if(a==0) return b==0?-1:-2; 140 if(b==0) return a==0?-1:-2; 141 return calc(a,b,4); 142 default: 143 assert(0); 144 return 0; 145 } 146 } 147 int calc_r2(int a,int b,int c)//找出x使得x c a = b 148 { 149 if(a==-2||b==-2) return -2; 150 if(a==-1||b==-1) return -1; 151 switch(c) 152 { 153 case 1: 154 return calc(b,a,2); 155 case 2: 156 return calc(b,a,1); 157 case 3: 158 if(a==0) return b==0?-1:-2; 159 return calc(b,a,4); 160 case 4: 161 if(a==0) return -2; 162 return calc(a,b,3); 163 default: 164 assert(0); 165 return 0; 166 } 167 } 168 void solve(int rt,int x)//x为要使得子树成为的值,-1->-1,-2->无解 169 { 170 //printf("t%d %d\n",rt,x); 171 if(nn[rt].type==0) an[nn[rt].num]=x; 172 else if(!nn[rt].ch[0]) solve(nn[rt].ch[1],calc_r1(0,x,nn[rt].type)); 173 else if(!nn[rt].ch[1]) assert(0);//solve(ch[0],x); 174 else 175 { 176 //if(x<0) 177 //printf("%d ch1 %d\n",rt,nn[nn[rt].ch[1]].d); 178 solve(nn[rt].ch[0],calc_r2(nn[nn[rt].ch[1]].d,x,nn[rt].type)); 179 //printf("%d ch0 %d\n",rt,nn[nn[rt].ch[0]].d); 180 solve(nn[rt].ch[1],calc_r1(nn[nn[rt].ch[0]].d,x,nn[rt].type)); 181 } 182 } 183 int rt; 184 int main() 185 { 186 bool fl=0; 187 int i,edpos=0,nowd,nowdep,t1; 188 ma['+']=1;ma['-']=2;ma['*']=3;ma['/']=4;ma['(']=5;ma[')']=6; 189 scanf("%d%d",&n,&md); 190 inv[1]=1; 191 for(i=2;i<md;i++) inv[i]=ll(md-md/i)*inv[md%i]%md; 192 scanf("%s",ss+1);len=strlen(ss+1); 193 for(i=1;i<=len;i++) 194 { 195 if(isdigit1(ss[i])) 196 { 197 edpos=i; 198 left=left*10+ss[i]-'0'; 199 } 200 else 201 break; 202 } 203 nowd=nowdep=0; 204 for(i=edpos+2;i<=len;i++) 205 { 206 if(isdigit1(ss[i])) 207 { 208 fl=1; 209 nowd=nowd*10+ss[i]-'0'; 210 } 211 else 212 { 213 if(fl) 214 { 215 fl=0; 216 ++plen; 217 pre[plen].d=nowd;pre[plen].type=0; 218 nowd=0; 219 } 220 ++plen; 221 pre[plen].type=ma[ss[i]]; 222 } 223 } 224 if(fl) 225 { 226 ++plen; 227 pre[plen].d=nowd;pre[plen].type=0; 228 } 229 for(i=1;i<=plen;i++) 230 { 231 if(pre[i].type==0&&pre[i].num!=-1) 232 { 233 pre[i].num=++mem; 234 nn[mem].type=0;nn[mem].d=pre[i].d;nn[mem].num=i; 235 } 236 } 237 for(i=1;i<=plen;i++) 238 { 239 if(pre[i].type==5) 240 { 241 st1.add_stack();st2.add_stack(); 242 } 243 else if(pre[i].type==6) 244 { 245 while(!st2.empty()) pop1(); 246 t1=st1.top();st1.pop(); 247 st1.del_stack();st2.del_stack(); 248 st1.push(t1); 249 } 250 else if(pre[i].type==0) 251 { 252 st1.push(pre[i].num); 253 } 254 else 255 { 256 while(!st2.empty()&&order[st2.top()]>=order[pre[i].type]) 257 pop1(); 258 st2.push(pre[i].type); 259 } 260 } 261 while(!st2.empty())pop1();//{printf("tt%d\n",st2.top());st2.pop();} 262 //while(!st1.empty()){printf("2t%d\n",st1.top());st1.pop();} 263 rt=st1.top();st1.pop(); 264 /* 265 for(i=1;i<=mem;i++) 266 { 267 printf("%d %d ",i,nn[i].type); 268 if(nn[i].type==0) printf("%d ",nn[i].d); 269 else printf("%d %d ",nn[i].ch[0],nn[i].ch[1]); 270 printf("%d ",nn[i].d); 271 puts(""); 272 } 273 */ 274 solve(rt,left); 275 for(i=1;i<=plen;i++) 276 if(pre[i].type==0) 277 { 278 if(an[i]==-2) puts("No Solution"); 279 else printf("%d\n",an[i]); 280 } 281 return 0; 282 }
事实上并不要的...只要把左括号放进栈,然后每一次做运算时保证不弹栈顶左括号(由于前置的-/+,可能弹不出来数,弹不出来了就弹0)
搞不清楚,还是前面那样写了..反正只是多点代码量,写写很快的
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 #include<vector> 5 #include<cmath> 6 using namespace std; 7 #define fi first 8 #define se second 9 #define mp make_pair 10 #define pb push_back 11 typedef long long ll; 12 typedef unsigned long long ull; 13 typedef pair<int,int> pii; 14 template<class T> 15 struct mstack 16 { 17 T d1[1001000]; 18 size_t d2[1001000],tp1,tp2; 19 mstack():tp1(0),tp2(1){d2[1]=0;} 20 bool empty(){return tp1==d2[tp2];} 21 T top(){return empty()?0:d1[tp1];} 22 void pop(){if(!empty())--tp1;} 23 void push(const T &x){d1[++tp1]=x;} 24 void del_stack(){--tp2;} 25 void add_stack(){d2[++tp2]=tp1;} 26 }; 27 mstack<double> st1; 28 mstack<char> st2; 29 int od[2333]; 30 double calc(double a,double b,char c) 31 { 32 //printf("tt%f %f %c\n",a,b,c); 33 switch(c) 34 { 35 case '+': 36 return a+b; 37 case '-': 38 return a-b; 39 case '*': 40 return a*b; 41 case '/': 42 return a/b; 43 case '^': 44 return pow(a,b); 45 default: 46 return 233; 47 } 48 } 49 char s[1001000]; 50 int len; 51 bool ok(char a,char b)//x a y b z是否先运算a 52 { 53 if(a=='^'&&b=='^') return 0; 54 return od[a]>=od[b]; 55 } 56 int main() 57 { 58 int i,tlen;double a,b,tt;char c; 59 od['+']=od['-']=1;od['*']=od['/']=2;od['^']=3; 60 scanf("%s",s);len=strlen(s); 61 for(i=0;i<len;) 62 { 63 //printf("ttt%d\n",i); 64 switch(s[i]) 65 { 66 case '(': 67 st1.add_stack();st2.add_stack(); 68 i++; 69 break; 70 case '+': 71 case '-': 72 case '*': 73 case '/': 74 case '^': 75 while(!st2.empty()&&ok(st2.top(),s[i])) 76 { 77 c=st2.top();st2.pop(); 78 b=st1.top();st1.pop(); 79 a=st1.top();st1.pop(); 80 st1.push(calc(a,b,c)); 81 } 82 st2.push(s[i]); 83 i++; 84 break; 85 case ')': 86 while(!st2.empty()) 87 { 88 c=st2.top();st2.pop(); 89 b=st1.top();st1.pop(); 90 a=st1.top();st1.pop(); 91 st1.push(calc(a,b,c)); 92 } 93 a=st1.top();st1.pop(); 94 st1.del_stack();st2.del_stack(); 95 st1.push(a); 96 i++; 97 break; 98 default: 99 sscanf(s+i,"%lf%n",&tt,&tlen); 100 st1.push(tt); 101 i+=tlen; 102 } 103 } 104 while(!st2.empty()) 105 { 106 c=st2.top();st2.pop(); 107 b=st1.top();st1.pop(); 108 a=st1.top();st1.pop(); 109 st1.push(calc(a,b,c)); 110 } 111 printf("%.2f",st1.top()); 112 return 0; 113 }
可以用sscanf直接读数字,用%n获取读取过程中消耗的字符数