题意:给定一个表达式,去除所有能去掉的括号
分析:因为是表达式,所以想套用LR(1)分析法和分解表达式,一步一步手动模拟去括号,结果总是拆东墙补西墙,搞不出来。
三天后看解题报告,标程是通过加括号来解决的,构造一颗二叉树,去掉所有括号,叶子是变量,非叶子其他的节点是运算符,节点的深度和他所在的括号数相同,
由于*和/的计算优先级比加和减高,所以当非叶子节点的运算符的优先级比孩子节点的高时,必须通过加括号来维护
pascal的标程是错(虽然它的文件名已经含有bug的单词,但是错的怎么能放到标程里!),有两处错误,我都发现过,可都只改了一处来测试,耗了一个下午,
看到java版的编程才恍然大悟,不自信啊!
第一处:由于同深度同优先级的时候是从左往右计算的,而它却写成从右往左。
第二处:1,在当非叶子节点的运算符的优先级比孩子节点的高,要加括号时,取反运算符不(false)应该影响括号内,它是沿用父节点的inverse;
2,而在同深度同优先级的时候,应该沿用父节点的inverse,它却是不影响(false);
#include<cstdio> #define MAXN 1010 using namespace std; struct ops { int l,r,pr; char op; }; ops o[MAXN]; char s[MAXN]; int k,p; int expr(); int createOps(int l,int r,char op,int pr) { k++; o[k].l=l; o[k].r=r; o[k].pr=pr; o[k].op=op; return k; } int factor() { int ret; if(s[p]>='a'&&s[p]<='z') ret=createOps(0,0,s[p++],3); else { p++; ret=expr(); p++; } return ret; } int term() { int l,r,ret; char op; l=factor(); while(s[p]=='*'||s[p]=='/') { op=s[p++]; r=factor(); l=createOps(l,r,op,2); } return l; } int expr() { int l,r; char op; l=term(); while(s[p]=='+'||s[p]=='-')//第一处,原为 if { op=s[p++]; r=term(); //第一处,原为 r=expr(); l=createOps(l,r,op,1); } return l; } void Print(int n,bool inverse) { int l,r; if(o[n].op>='a'&&o[n].op<='z') { putchar(o[n].op); return; } l=o[n].l; r=o[n].r; if(o[l].pr>o[n].pr) Print(l,false); else if(o[l].pr<o[n].pr) { putchar('('); Print(l,false);//第二处的第一点 ,原为 Print(l,inverse); putchar(')'); } else Print(l,inverse);//第二处的第二点 ,原为 Print(l,false); if(!inverse) putchar(o[n].op); else if(o[n].op=='+') putchar('-'); else if(o[n].op=='-') putchar('+'); else if(o[n].op=='*') putchar('/'); else putchar('*'); if(o[r].pr>o[n].pr) Print(r,false); else if(o[r].pr<o[n].pr) { putchar('('); Print(r,false); putchar(')'); } else//如果不改第一处的话,错误就会在这里产生 { if(o[n].op=='-'||o[n].op=='/') inverse=!inverse; Print(r,inverse); } } int main() { gets(s); k=p=0; int n=expr(); Print(n,false); return 0; }