1 程序简要图解
2 分块说明
1)生成普通算式并计算
生成:生成第一个运算数 -> for(auto i = 1:cnt)先生成一个运算符,再生成一个运算数(ps:这样可以保证避免出现连乘连除、运算过程为负数、不能整除的情况)-> 将该序列转化为String 以便最后输出
string tmp="";
memset(num,-1,sizeof(num));
//产生随机数
num[0]=res(1,80);
memset(op,-1,sizeof(op));
// puts("1");
//普通算式
if(flag==0) {
for(int i=0; i<cnt; i++) {
//int nop=res(0,3);
//取消连乘连除操作
// puts("!!!!");
// printf("i: %d\n",i);
if(i>0&&(op[i-1]==2||op[i-1]==3))
op[i]=res(0,1);
else
op[i]=res(0,3);
// printf("op: %d\n",op[i]);
//加减乘除特殊处理
if(op[i]==0) {
num[i+1]=res(0,100-num[i]);
// puts("1.1");
} else if(op[i]==1) {
num[i+1]=res(0,num[i]);
// puts("1.2");
} else if(op[i]==2) {
num[i]=res(1,30);
num[i+1]=res(1,100/num[i]);
// puts("1.3");
} else if(op[i]==3) {
num[i+1]=res(1,10);
num[i]=num[i+1]*res(2,10);
// puts("1.4");
}
}
//转化字符串
char tt[10];
memset(tt,'\0',sizeof(tt));
itoa(num[0],tt,10);
string t=tt;
tmp+=t;
for(int i=0; i<cnt; i++) {
if(op[i]==0)
tmp+="+";
if(op[i]==1)
tmp+="-";
if(op[i]==2)
tmp+="*";
if(op[i]==3)
tmp+="/";
memset(tt,'\0',sizeof(tt));
itoa(num[i+1],tt,10);
t=tt;
tmp+=t;
}
}
计算:将该中缀表达式用栈转化为后缀表达式并返回结果,若结果不属于1~100则重新生成
2)生成带括号的算式
同理1),注意特判一下括号前后的运算符以保证满足要求
//带括号
if(flag==1) {
int pos=res(0,2);
for(int i=0; i<cnt; i++) {
if(i>0&&(op[i-1]==2||op[i-1]==3))
op[i]=res(0,1);
else
op[i]=res(0,3);
//特判
if(pos==2||pos==1||pos==0) {
if(i==2||i==0||i==1) {
op[i]=res(0,2);
while(op[i]==1) {
op[i]=res(0,2);
}
}
if(cnt>=4) {
if(i==3) {
op[i]=res(0,2);
while(op[i]==1) {
op[i]=res(0,2);
}
}
}
}
if(op[i]==0) {
num[i+1]=res(0,100-num[i]);
// puts("1.1");
} else if(op[i]==1) {
num[i+1]=res(0,num[i]);
// puts("1.2");
} else if(op[i]==2) {
num[i]=res(1,30);
num[i+1]=res(1,100/num[i]);
// puts("1.3");
} else if(op[i]==3) {
num[i+1]=res(1,10);
num[i]=num[i+1]*res(2,10);
// puts("1.4");
}
}
//转化字符串
// string tmp="";
if(pos==1)
tmp+="(";
if(pos==0||pos==1)
tmp+="(";
char tt[10];
memset(tt,'\0',sizeof(tt));
itoa(num[0],tt,10);
string t=tt;
tmp+=t;
for(int i=0; i<cnt; i++) {
if(op[i]==0)
tmp+="+";
if(op[i]==1)
tmp+="-";
if(op[i]==2)
tmp+="*";
if(op[i]==3)
tmp+="/";
if(pos==0) {
if(i==1)
tmp+="(";
}
if(pos==2) {
if(i==0)
tmp+="((";
}
memset(tt,'\0',sizeof(tt));
itoa(num[i+1],tt,10);
t=tt;
tmp+=t;
if(pos==0) {
if(i==0)
tmp+=")";
if(i==2)
tmp+=")";
}
if(pos==1) {
if(i==0)
tmp+=")";
if(i==1)
tmp+=")";
}
if(pos==2) {
if(i==1)
tmp+=")";
if(i==2)
tmp+=")";
}
}
}
3)生成分数运算式
因为分数只加减,所以可以每生成一组运算符和数,用gcd化简后就计算结果,判断是否满足条件,持续生成即可,最终即得到运算结果。
3 遇到的问题
1)代码重用性需进一步提高,有些地方还是出现了相同的代码,但若将其独立成函数再调用,有时会出现错误。
2)用后缀表达式计算带括号的式子结果时出现了有些式子只算括号里的值,有些式子只算括号外的值这种情况。其原因是如果当前是运算符而上一个是运算数,那么会把tmp=0加入进栈,造成运算错误,特判即可解决
if(flag==1) {
for(int i=0; i<len; i++) {
if(s[i]>='0'&&s[i]<='9') {
tmp=tmp*10+s[i]-'0';
if(i==len-1)
stn.push(tmp),tmp=0;
} else {
// 解决了
if(s[i] != '(' && (s[i - 1]>='0'&&s[i - 1]<='9')) {
stn.push(tmp);
tmp=0;
}
if(s[i]=='(')
sto.push(s[i]);
else if(s[i]==')') {
while(sto.top()!='(') {
int b=stn.top();
stn.pop();
int a=stn.top();
stn.pop();
char c=sto.top();
sto.pop();
int val=getans(a,b,c);
stn.push(val);
}
sto.pop();
} else {
while(true) {
if(sto.empty() || sto.top() == '(' || change(s[i]) > change(sto.top())) {
sto.push(s[i]);
break;
}
int b=stn.top();
stn.pop();
int a=stn.top();
stn.pop();
char c=sto.top();
sto.pop();
int val=getans(a,b,c);
stn.push(val);
}
}
}
// if(!stn.empty()) printf("top:%d\n", stn.top());
}
while(!sto.empty()) {
int b=stn.top();
stn.pop();
int a=stn.top();
stn.pop();
char c=sto.top();
sto.pop();
int val=getans(a,b,c);
stn.push(val);
}
return stn.top();
}
3)分数要求中,只保证了是真分数形式,但仍存在问题,即运算结果的分母无法控制在1~100以内,因为通分和求gcd会使分母扩大难以控制范围,强制控制的话会RE,未解决此问题也在查看其他博客学习,待解决。
4 result.txt 部分截图(主要是为了看一下除号)
5 感触和收获
1)debug到头大,毫无码力的样子
2)前期设计真的太太太重要了!!!如果总体想法考虑不全面真的debug三天也没办法改好,几乎要推倒重来。关于设计方面觉得自己不是特别逻辑,经常想到什么写什么,然后再把这一堆东西强硬地组织起来,没什么体系和方法论。可能学完uml和软导会好一丢丢……?
3)听了同学们的分享觉得用好java挺重要的,添加后续内容一类用java比较方便,c++就不太可持久化发展
6 psp
有想到的再补充