四则运算三
这一周,老师提出了新的要求:
1.学生写的程序必须能判定,用户输入的答案是否正确;
- 例如程序输出:20-5=?用户输入15,那么程序就会反馈正确,然后继续出题。直到三十道题目结束,程序最后告诉用户做对了几道题。
2.程序必须能够处理四种运算的混合算式;
- 20-5*2=? 正确答案是10.
- 20-5*2+9/3=? 正确答案是13.
注意:
连续的减法和除法,应该遵循左结合的规定。
连续除法要打括号,否则会引起歧义。
针对这一次的练习,只需只需在上一次的基础上加上表达的式的求值即可,只是就需要用到数据结构中的栈来解决。说是简单,但是实现起来却不容易,数据结构一直是我头疼的东西。和我的同学比起来真的是自愧不如,这次他和我一直,询问了他许久。
最后在上一次的基础上,增加了一个表达式求解的模块,具体代码如下:
1 // 按要求随机生成四则运算 王世强 2015/3/15 2 #include<iostream> 3 #include<stdlib.h> 4 #include<iomanip> 5 #include<time.h> 6 #include<stdio.h> 7 #include"math.h" 8 #define true 1 9 #define false 0 10 #define OPSETSIZE 7 11 #define random() (rand()%100000) 12 #include"string.h" 13 typedef int Status; 14 using namespace std; 15 16 unsigned char Prior[7][7] = 17 { // 运算符优先级表 18 // '+' '-' '*' '/' '(' ')' '#' 19 /*'+'*/'>','>','<','<','<','>','>', 20 /*'-'*/'>','>','<','<','<','>','>', 21 /*'*'*/'>','>','>','>','<','>','>', 22 /*'/'*/'>','>','>','>','<','>','>', 23 /*'('*/'<','<','<','<','<','=',' ', 24 /*')'*/'>','>','>','>',' ','>','>', 25 /*'#'*/'<','<','<','<','<',' ','=', 26 }; 27 28 typedef struct StackChar 29 { 30 char c; 31 struct StackChar *next; 32 }SC; //StackChar类型的结点SC 33 34 typedef struct StackFloat 35 { 36 float f; 37 struct StackFloat *next; 38 }SF; //StackFloat类型的结点SF 39 40 SC *Push(SC *s,char c) //SC类型的指针Push,返回p 41 { 42 SC *p=(SC*)malloc(sizeof(SC)); 43 p->c=c; 44 p->next=s; 45 return p; 46 } 47 48 SF *Push(SF *s,float f) //SF类型的指针Push,返回p 49 { 50 SF *p=(SF*)malloc(sizeof(SF)); 51 p->f=f; 52 p->next=s; 53 return p; 54 } 55 56 SC *Pop(SC *s) //SC类型的指针Pop 57 { 58 SC *q=s; 59 s=s->next; 60 free(q); 61 return s; 62 } 63 64 SF *Pop(SF *s) //SF类型的指针Pop 65 { 66 SF *q=s; 67 s=s->next; 68 free(q); 69 return s; 70 } 71 72 float Operate(float a,unsigned char theta, float b) //计算函数Operate 73 { 74 switch(theta) 75 { 76 case '+': return a+b; 77 case '-': return a-b; 78 case '*': return a*b; 79 case '/': return a/b; 80 default : return 0; 81 } 82 } 83 84 char OPSET[OPSETSIZE]={'+','-','*','/','(',')','#'}; 85 86 Status In(char Test,char *TestOp) 87 { 88 int Find=false; 89 for (int i=0; i< OPSETSIZE; i++) 90 { 91 if(Test == TestOp[i]) 92 Find= true; 93 } 94 return Find; 95 } 96 97 Status ReturnOpOrd(char op,char *TestOp) 98 { 99 for(int i=0; i< OPSETSIZE; i++) 100 { 101 if (op == TestOp[i]) 102 return i; 103 } 104 } 105 106 char precede(char Aop, char Bop) 107 { 108 return Prior[ReturnOpOrd(Aop,OPSET)][ReturnOpOrd(Bop,OPSET)]; 109 } 110 111 float EvaluateExpression(char* MyExpression) 112 { 113 // 算术表达式求值的算符优先算法 114 // 设OPTR和OPND分别为运算符栈和运算数栈,OP为运算符集合 115 SC *OPTR=NULL; // 运算符栈,字符元素 116 SF *OPND=NULL; // 运算数栈,实数元素 117 char TempData[20]; 118 float Data,a,b; 119 char theta,*c,Dr[]={'#','\0'}; 120 OPTR=Push(OPTR,'#'); 121 c=strcat(MyExpression,Dr); 122 strcpy(TempData,"\0");//字符串拷贝函数 123 while (*c!= '#' || OPTR->c!='#') 124 { 125 if (!In(*c, OPSET)) 126 { 127 Dr[0]=*c; 128 strcat(TempData,Dr); //字符串连接函数 129 c++; 130 if (In(*c, OPSET)) 131 { 132 Data=atof(TempData); //字符串转换函数(double) 133 OPND=Push(OPND, Data); 134 strcpy(TempData,"\0"); 135 } 136 } 137 else // 不是运算符则进栈 138 { 139 switch (precede(OPTR->c, *c)) 140 { 141 case '<': // 栈顶元素优先级低 142 OPTR=Push(OPTR, *c); 143 c++; 144 break; 145 case '=': // 脱括号并接收下一字符 146 OPTR=Pop(OPTR); 147 c++; 148 break; 149 case '>': // 退栈并将运算结果入栈 150 theta=OPTR->c;OPTR=Pop(OPTR); 151 b=OPND->f;OPND=Pop(OPND); 152 a=OPND->f;OPND=Pop(OPND); 153 OPND=Push(OPND, Operate(a, theta, b)); 154 break; 155 } //switch 156 } 157 } //while 158 return OPND->f; 159 } //EvaluateExpression 160 161 //符号生成 162 char create_symbol(int n) 163 { 164 int n1,j; 165 char symbol[1]; 166 if(n==0) 167 { 168 n1=2; 169 } 170 else if(n=1) 171 { 172 n1=4; 173 } 174 j=random()%n1; 175 if(j==0) symbol[0]='+'; 176 else if(j==1) symbol[0]='-'; 177 else if(j==2) symbol[0]='*'; 178 else symbol[0]='/'; 179 return symbol[0]; 180 } 181 //把数字转换成字符串型 182 string int_string(int number) 183 { 184 char str[200]; 185 itoa(number,str,10); 186 string str_=str; 187 return str_; 188 } 189 //真分数合成一个字符串 190 string combination1(string str1,string str2,char k) 191 { 192 string equation; 193 equation='('+str1+k+str2+')'; 194 return equation; 195 } 196 //新生成一个数 197 string create_num(int proper_fs,int range) 198 { 199 int num,num1,num2,fs; 200 string str_num,str_num1,str_num2; 201 num=random()%range+1; 202 str_num=int_string(num); 203 if(proper_fs==1) 204 { 205 fs=random()%3; 206 if(fs==1)//判断是否生成真分数 207 { 208 for(;;) 209 { 210 num1=random()%range+1; 211 num2=random()%range+1; 212 if(num1<num2) break; 213 } 214 str_num1=int_string(num1); 215 str_num2=int_string(num2); 216 str_num=combination1(str_num1,str_num2,'/'); 217 } 218 } 219 return str_num; 220 } 221 //运算式转换成一个字符串 222 string combination(string str1,string str2,char k) 223 { 224 string equation; 225 equation=str1+k+str2; 226 return equation; 227 } 228 229 //得出正确答案 230 float get_ans(string str) 231 { 232 int len; 233 float ans; 234 len=str.length(); 235 char num[len]; 236 for(int j=0;j<len;j++) 237 { 238 num[j]=str[j]; 239 } 240 //用堆栈解决。。。 241 ans=EvaluateExpression(num); 242 return ans; 243 } 244 //主函数 245 int main() 246 { 247 srand((int)time(NULL)); //设置时间种子 ,使得程序每次运行的结果都不同 248 int num1,num2,num3,num4,count,n,change,amount,shuchu,range,j,repeat=0,bracket,proper_fs,right=0,wrong=0; 249 string str_num1,str_num2,temp; 250 float Answer,InputAns; 251 cout<<"有无乘除法?1有,0没有:"<<endl; 252 cin>>n; 253 cout<<"是否有括号?1有,0没有:"<<endl; 254 cin>>bracket; 255 cout<<"是否有真分数?1有,0没有:"<<endl; 256 cin>>proper_fs; 257 cout<<"请输入数字范围:"<<endl; 258 cin>>range; 259 cout<<"请输入出题数量:"<<endl; 260 cin>>amount; 261 string Equation[amount]; 262 char symbol; 263 cout<<amount<<"道四则运算题如下:"<<endl; 264 for(int i=0;i<amount;i++) 265 { 266 count=random()%3+2; 267 str_num1=create_num(proper_fs,range); 268 str_num2=create_num(proper_fs,range); 269 symbol=create_symbol(n); 270 Equation[i]=combination(str_num1,str_num2,symbol); 271 if(count>2) 272 { 273 for(count;count>2;count--) 274 { 275 symbol=create_symbol(n); 276 str_num1=Equation[i]; 277 if(bracket==1) 278 { 279 change=random()%3; 280 if(change==0) 281 { 282 str_num1='('+str_num1+')'; 283 } 284 } 285 symbol=create_symbol(n); 286 str_num2=create_num(proper_fs,range); 287 change=random()%2; 288 if(change==0) 289 { 290 temp=str_num1; 291 str_num1=str_num2; 292 str_num2=temp; 293 } 294 Equation[i]=combination(str_num1,str_num2,symbol); 295 } 296 } 297 //判断是否重复 298 for(j=0;j<i;j++) 299 { 300 if(Equation[j]==Equation[i]) 301 { 302 i=i-1; 303 repeat=1; 304 break; 305 } 306 } 307 if(repeat!=1)//若不重复,则输出 308 { 309 cout<<Equation[i]<<"="; 310 //判断结果是否正确 311 cin>>InputAns; 312 Answer=get_ans(Equation[i]); 313 Answer*=100; 314 int temp=(int)Answer; 315 Answer=((double)temp)/100.00; 316 if(InputAns==Answer) 317 { 318 cout<<"回答正确!"; 319 right++; 320 } 321 else 322 { 323 cout<<"回答错误!正确答案为"; 324 cout<<setprecision(2)<<fixed<<Answer; 325 wrong++; 326 } 327 cout<<endl; 328 } 329 } 330 cout<<"一共答对"<<right<<"道题,答错"<<wrong<<"道题。"<<endl; 331 }
下面是运行结果截图:
总结:这次的练习,熟悉了数据结构的知识,但是对我来说还是一个空缺部分,希望能够补上。
这次和我结队的同学是高逸凡,附一张我俩合作时的照片
项目计划总结:
日期&&任务 | 听课 | 编写程序 | 阅读相关书籍 | 网上查找资料 | 日总计 |
周一 | 2 | 3 | 2 | 7 | |
周二 | 2 | 2 | 4 | ||
周三 | |||||
周四 | 2 | 2 | 4 | ||
周五 | 2 | 1 | 3 | ||
周六 | 2 | 2 | |||
周日 | |||||
周总计 | 4 | 9 | 5 | 2 | 20 |
时间记录日志:
日期 | 开始时间 | 结束时间 | 中断时间 | 净时间 | 活动 | 备注 |
3/4 | 14:00 | 15:50 | 10 | 100 | 听课 | 软件工程上课 |
16:00 | 18:20 | 140 | 编写程序 | 任务3 | ||
19:00 | 20:00 | 10 | 50 | 编写程序 | 任务3 | |
20:00 | 21:00 | 60 | 网上查找资料,阅读 | 《构建之法》 | ||
3/15 | 16:00 | 18:00 | 10 | 110 | 查资料,编写程序 | 作业3 |
19:00 | 21:10 | 10 | 120 | 编写程序 | 任务3 | |
3/16 | ||||||
3/17 | 14:00 | 15:50 | 10 | 100 | 听课 | 软件工程上课 |
19:00 | 21:20 | 20 | 100 | 查资料,编写程序 | 休息,聊天,作业3 | |
3/18 | 8:00 | 10:05 | 5 | 120 | 修改,编程 | 任务3 |
16:10 | 17:20 | 10 | 60 | 阅读 | 《构建之法》 | |
3/19 | 19:20 | 21:50 | 30 | 120 | 修改程序,写博客 | 休息,谈论问题,修改,发表博客 |
3/13 | 19:00 | 19:30 | 30 | 阅读书籍 | 计划阅读《梦断代码》 |
缺陷记录日志:
日期 | 编号 | 类型 | 引入阶段 | 排除阶段 | 修复时间 | 修复缺陷 |
3/18 | 1 | 20 | 编码 | 编译 | 120min | |
描述:栈的定义及使用,总是报错! |