一,题目要求(四则运算3)
1、学生写的程序必须能判定用户的输入答案是否正确,例如程序输出:20 – 5 = ?用户输入15,那么程序就会反馈正确,然后继续出题。直到 30 道题目结束,程序最后告诉用户作对了几道题。
2、程序必须能处理四种运算的混合算式;
n20 – 5 * 2 =? 正确答案是10.
n20– 5 * 2 + 9 / 3 = ? 正确答案是13
3、注意:连续的减法和除法,应该遵守左结合的规定。 连续除法要打括号,否则会引起歧义
二、设计思想
使用栈来实现,因为栈的“先进后出”的特性正好满足了能通过后缀表达式去计算出四则运算式子的结果。而后缀表达式的转化也能使用栈对中缀表达式进行操作从而转化。关于题目的保存和提取可以使用文件读写函数,这样就可以判断用户的答案的正确性了,关于提取,加一个判断是否为操作符的函数就ok了,可以尝试使用类来封装做题的这个程序,在main文件里只加是否继续就ok,
三、源程序代码
类的头文件
1 #pragma once 2 #include<iostream> 3 #include<string> 4 #include<time.h> 5 #include <stdio.h> 6 #include<fstream> 7 #include<cmath> 8 #include<sstream> 9 #include<strstream> 10 #include<math.h> 11 #include<iomanip> 12 #define MAX 100 13 #define False 0 14 #define True 1 15 using namespace std; 16 typedef string SelemType; 17 typedef struct{ 18 SelemType *base; 19 SelemType *top; 20 int stacksize; 21 }Sqstack; 22 23 class ArithMath 24 { 25 private: 26 Sqstack s; 27 string str1[4]; //运算符数组,存储+ - * / 28 int n,m; 29 int num[6]; //随机生成的操作数 30 char str2[25]; //整数转化为的字符数组 31 char str3[25]; //整数转化为的字符数组 32 string str4[100]; 33 int OperatorNum[1000]; //运算符数组,每生成一个运算符存进数组 34 35 public: 36 ArithMath(void); 37 ~ArithMath(void); 38 void InitStack(Sqstack &s) //栈的初始化 39 { 40 s.base=new SelemType[MAX]; 41 if(!s.base)exit(1); 42 s.top=s.base; 43 s.stacksize =MAX; 44 } 45 void Push(Sqstack &s,SelemType e) //压入 46 { 47 if(s.top-s.base==s.stacksize) 48 exit(1); 49 *s.top++=e; 50 } 51 void Pop(Sqstack &s,SelemType &e) //弹出 52 { 53 if(s.top==s.base) 54 exit(1); 55 e=*--s.top; 56 } 57 SelemType GetTop(Sqstack &s) //取顶 58 { 59 if(s.top==s.base) 60 exit(1); 61 return *(s.top-1); 62 } 63 64 void workNum();//控制中心函数 65 void changeNum(int n,int y,int min,int max); 66 void changeNum1(int n,int min,int max); 67 int In(SelemType);//判断是否为运算符 68 SelemType Operate(SelemType a1,SelemType theta,SelemType b1);//计算 69 char Precede(string theta1,string theta2);//运算符的计算顺序判断 70 string TiQuString(string,int &); 71 string OPeration(string); 72 void Input(int n,int p,int min,int max,int &j,int &q); 73 void Input1(int n,int p,int min,int max,int &j,int &q); 74 void sort(int min,int max); 75 void sort1(int min,int max); 76 void Simplification(int &m,int &n) ; 77 void Input2(int n,int p,int min,int max,int &j,int &q); 78 };
类的cpp文件
1 #include "ArithMath.h" 2 3 ArithMath::ArithMath(void) 4 { 5 str1[0]='+'; 6 str1[1]='-'; 7 str1[2]='*'; 8 str1[3]='/'; 9 } 10 11 ArithMath::~ArithMath(void) 12 { 13 14 } 15 16 17 int ArithMath::In(SelemType ch) //判断是否为运算符 18 { 19 if(ch=="+"||ch=="-"||ch=="*"||ch=="/"||ch=="("||ch==")"||ch=="#") 20 return True; 21 else 22 return False; 23 } 24 SelemType ArithMath::Operate(SelemType a1,SelemType theta,SelemType b1) //计算 25 { 26 stringstream ss; 27 SelemType c1; 28 double m1,m2; 29 double m3,m4; 30 m1=atof(a1.c_str()); 31 m2=atof(b1.c_str()); 32 if(theta=="+") 33 m3=m1+m2; 34 else if(theta=="-") 35 m3=m1-m2; 36 else if(theta=="*") 37 m3=m1*m2; 38 else if(theta=="/") 39 m3=m1/m2; 40 m4=double((int)(m3*100))/100.0; 41 ss<<m4; 42 ss>>c1; 43 return c1; 44 } 45 char ArithMath::Precede(string theta1,string theta2) //运算符的计算顺序判断 46 { 47 char chx; 48 if(theta1=="+") 49 { 50 if(theta2=="*"||theta2=="/"||theta2=="(") 51 chx = '<'; 52 else 53 chx = '>'; 54 } 55 else if(theta1=="-") 56 { 57 if(theta2=="*"||theta2=="/"||theta2=="(") 58 chx = '<'; 59 else 60 chx = '>'; 61 } 62 else if(theta1=="*") 63 { 64 if(theta2=="(") 65 chx = '<'; 66 else 67 chx = '>'; 68 } 69 else if(theta1=="/") 70 { 71 if(theta2=="(") 72 chx = '<'; 73 else 74 chx = '>'; 75 } 76 else if(theta1=="(") 77 { 78 if(theta2==")") 79 chx = '='; 80 else if(theta2=="#") 81 chx='$'; 82 else 83 chx = '<'; 84 } 85 else if(theta1==")") 86 { 87 if(theta2=="(") 88 chx = '$'; 89 else 90 chx = '>'; 91 } 92 else if(theta1=="#") 93 { 94 if(theta2=="#") 95 chx = '='; 96 else if(theta2==")") 97 chx='$'; 98 else 99 chx = '<'; 100 } 101 return chx; 102 } 103 string ArithMath::TiQuString(string str,int &i) 104 { 105 string ch; 106 char *q; 107 string p; 108 p=str; 109 q=&p[i]; 110 ch=ch+*q; 111 if((*q>='0')&&(*q<='9')) 112 { 113 i++; 114 int j=1; 115 while((*(q+j)>='0')&&(*(q+j)<='9')) 116 { 117 ch=ch+*(q+j); 118 j++; 119 } 120 i=i+j-1; 121 } 122 else 123 { 124 ch=*q; 125 i++; 126 } 127 return ch; 128 } 129 string ArithMath::OPeration(string str) 130 { 131 132 string str1; 133 str1=str+"#"; 134 int i=0; 135 string ch; 136 ch=TiQuString(str1,i); 137 SelemType theta,x1,a1,b1; 138 Sqstack OPND,OPTR; 139 InitStack(OPTR); 140 InitStack(OPND); 141 Push(OPTR,"#"); 142 while(ch!="#"||GetTop(OPTR)!="#") 143 { 144 int f; 145 f=In(ch); 146 if(f!=True) 147 { 148 Push(OPND,ch); 149 ch=TiQuString(str1,i); 150 } 151 else 152 { 153 switch(Precede(GetTop(OPTR),ch)) 154 { 155 case '<': 156 { 157 Push(OPTR,ch); 158 ch=TiQuString(str1,i); 159 break; 160 } 161 case '>': 162 { 163 Pop(OPTR,theta); 164 Pop(OPND,b1);Pop(OPND,a1); 165 Push(OPND,Operate(a1,theta,b1)); 166 break; 167 } 168 case '=': 169 { 170 Pop(OPTR,x1); 171 ch=TiQuString(str1,i); 172 break; 173 } 174 case '$': 175 { 176 cout<<"该表达式有错"; 177 break; 178 } 179 default:break; 180 } 181 } 182 } 183 return GetTop(OPND); 184 185 } 186 void ArithMath::Input(int n,int p,int min,int max,int &j,int &q) 187 { 188 int num1,num2,num3,num4,num5; //随机数 189 int c=0; //指向第一个运算符数组的下标 190 int s=0; //括号的个数 191 string str; 192 ofstream outfile; 193 outfile.open("a.txt",ios::app); 194 if(!outfile) 195 { 196 cerr<<"OPEN ERROR!"<<endl; 197 exit(0); 198 } 199 num1=rand()%(max-min+1)+min; 200 num2=rand()%(max-min+1)+min; 201 num3=rand()%4; //随机数指向运算符数组的下标 202 itoa(num1,str2,10); //整数转化为字符数组 203 itoa(num2,str3,10); //整数转化为字符数组 204 str=str2+str1[num3]+str3; //生成表达式 205 OperatorNum[c]=num3; //当前生成的符号存入OperatorNum数组里 206 c++; 207 n=n-2; //消耗了两个操作数 208 while(n!=0) //当n不等于0时,循环生成str,即表达式+符号+表达式的形式 209 { 210 num4=rand()%2; 211 if(num4==0) //上一个str放在符号的左边 212 { 213 num5=rand()%2; 214 if(s<=3) 215 { 216 if(num5==0) //上一个str不加括号 217 { 218 num3=rand()%4; 219 OperatorNum[c]=num3; 220 c++; 221 num1=rand()%(max-min+1)+min; 222 itoa(num1,str2,10); 223 if((num3==3)&&(OperatorNum[c-2]==3)) //避免生成6/3/2的形式 224 str="("+str+")"+str1[num3]+str2; 225 else 226 str=str+str1[num3]+str2; 227 } 228 else //上一个str加括号 229 { 230 num3=rand()%4; 231 num1=rand()%(max-min+1)+min; 232 itoa(num1,str2,10); 233 str="("+str+")"+str1[num3]+str2; 234 s++; 235 } 236 } 237 else 238 { 239 num3=rand()%4; 240 OperatorNum[c]=num3; 241 c++; 242 num1=rand()%(max-min+1)+min; 243 itoa(num1,str2,10); 244 if((num3==3)&&(OperatorNum[c-2]==3)) //避免生成6/3/2的形式 245 str="("+str+")"+str1[num3]+str2; 246 else 247 str=str+str1[num3]+str2; 248 } 249 } 250 else //上一个str放在符号的右边 251 { 252 num5=rand()%2; 253 if(s<=3) 254 { 255 if(num5==0) // 上一个str不加括 256 { 257 num3=rand()%4; 258 OperatorNum[c]=num3; 259 c++; 260 num1=rand()%(max-min+1)+min; 261 itoa(num1,str2,10); 262 if((num3==3)&&(OperatorNum[c-2]==3)) 263 str=str2+str1[num3]+"("+str+")"; 264 else 265 str=str2+str1[num3]+str; 266 } 267 else //上一个str加括号 268 { 269 num3=rand()%4; 270 num1=rand()%(max-min+1)+min; 271 itoa(num1,str2,10); 272 str=str2+str1[num3]+"("+str+")"; 273 s++; 274 } 275 } 276 else 277 { 278 num3=rand()%4; 279 OperatorNum[c]=num3; 280 c++; 281 num1=rand()%(max-min+1)+min; 282 itoa(num1,str2,10); 283 if((num3==3)&&(OperatorNum[c-2]==3)) 284 str=str2+str1[num3]+"("+str+")"; 285 else 286 str=str2+str1[num3]+str; 287 } 288 } 289 n--; //消耗一个操作数 290 } 291 string result1,result2; //result1表示用户输入的答案,result2表示程序计算的结果 292 str4[p]=str; //把str存入字符串数组str4中 293 for(int i=0;i<p;i++) //查询四则运算式是否有重复 294 if(str4[i]==str4[p]) 295 Input(m,p,min,max,j,q); 296 cout<<str4[p]<<"="; 297 result2=OPeration(str); //计算四则表达式 298 cin>>result1; 299 if(result1==result2) //判断结果是否正确 300 { 301 cout<<"计算正确"; 302 j++; 303 } 304 else 305 { 306 cout<<"计算错误,答案是"<<setprecision(2)<<fixed<<result2; 307 q++; 308 } 309 outfile<<str4[p]<<endl; 310 cout<<endl; 311 } 312 void ArithMath::Input1(int n,int p,int min,int max,int &j,int &q) 313 { 314 int num1,num2,num3,num4; 315 int c=0; 316 int s=0; 317 string str; 318 ofstream outfile; 319 outfile.open("a.txt",ios::app); 320 if(!outfile) 321 { 322 cerr<<"OPEN ERROR!"<<endl; 323 exit(0); 324 } 325 num1=rand()%(max-min+1)+min; 326 num2=rand()%(max-min+1)+min; 327 num3=rand()%4; 328 itoa(num1,str2,10); 329 itoa(num2,str3,10); 330 str=str2+str1[num3]+str3; 331 OperatorNum[c]=num3; 332 c++; 333 n=n-2; 334 while(n!=0) //当n不等于0时,循环生成str,即表达式+符号+表达式的形式 335 { 336 num4=rand()%2; 337 if(num4==0) //上一个str放在符号的左边 338 { 339 num3=rand()%4; 340 OperatorNum[c]=num3; 341 c++; 342 num1=rand()%(max-min+1)+min; 343 itoa(num1,str2,10); 344 if((num3==3)&&(OperatorNum[c-2]==3)) //避免生成6/3/2的形式 345 str="("+str+")"+str1[num3]+str2; 346 else 347 str=str+str1[num3]+str2; 348 } 349 else //上一个str放在符号的右边 350 { 351 num3=rand()%4; 352 OperatorNum[c]=num3; 353 c++; 354 num1=rand()%(max-min+1)+min; 355 itoa(num1,str2,10); 356 if((num3==3)&&(OperatorNum[c-2]==3)) 357 str=str2+str1[num3]+"("+str+")"; 358 else 359 str=str2+str1[num3]+str; 360 } 361 n--; 362 } 363 string result1,result2; 364 str4[p]=str; //把str存入字符串数组str4中 365 for(int i=0;i<p;i++) //查询四则运算式是否有重复 366 if(str4[i]==str4[p]) 367 Input(m,p,min,max,j,q); 368 cout<<str4[p]<<"="; 369 result2=OPeration(str); 370 cin>>result1; 371 if(result1==result2) 372 { 373 cout<<"计算正确"; 374 j++; 375 } 376 else 377 { 378 cout<<"计算错误,答案是"<<setprecision(2)<<fixed<<result2; 379 q++; 380 } 381 outfile<<str4[p]<<endl; 382 cout<<endl; 383 } 384 void ArithMath::sort(int min,int max){ //生成四个随机数并排序 385 num[0]=rand()%(max-min+1)+min; 386 num[1]=rand()%(max-min+1)+min; 387 num[2]=rand()%(max-min+1)+min; 388 num[3]=rand()%(max-min+1)+min; 389 for(int i=0;i<4;i++){ 390 for(int j=0;j<i;j++){ 391 if(num[i]>num[j]) 392 { 393 int temp=0; 394 temp=num[i]; 395 num[i]=num[j]; 396 num[j]=temp; 397 } 398 } 399 } 400 } 401 void ArithMath::sort1(int min,int max) //生成两个随机数,并排序 402 { 403 num[4]=rand()%(max-min+1)+min; 404 num[5]=rand()%(max-min+1)+min; 405 for(int i=4;i<6;i++){ 406 for(int j=4;j<i;j++){ 407 if(num[i]>num[j]) 408 { 409 int temp=0; 410 temp=num[i]; 411 num[i]=num[j]; 412 num[j]=temp; 413 } 414 } 415 } 416 } 417 void ArithMath::Simplification(int &m,int &n) //真分数化简 418 { 419 int x,y,i,p; //公约数p 420 if(m>=n) 421 { 422 x=n; 423 y=m; 424 } 425 if(m<n) 426 { 427 x=m; 428 y=n; 429 } 430 for(i=x;i>0;i--) 431 { 432 if(x%i==0&&y%i==0) 433 { 434 p=i; 435 break; 436 } 437 } 438 m=m/p; 439 n=n/p; 440 } 441 void ArithMath::Input2(int n,int p,int min,int max,int &j,int &q) 442 { 443 int num3,num4,s=0; 444 string str,strr2,strr3,str5,str6,str7,str8,str9; 445 stringstream ss1,ss2,ss3,ss4,ss5,ss6,ss7,ss8; 446 ofstream outfile; 447 outfile.open("a.txt",ios::app); 448 if(!outfile) 449 { 450 cerr<<"OPEN ERROR!"<<endl; 451 exit(0); 452 } 453 num3=rand()%4; 454 sort(min,max); 455 Simplification(num[0],num[3]); 456 Simplification(num[1],num[2]); 457 ss1<<num[0]; 458 ss1>>strr2; 459 ss2<<num[1]; 460 ss2>>strr3; 461 ss3<<num[2]; 462 ss3>>str5; 463 ss4<<num[3]; 464 ss4>>str6; 465 if((str5!=strr3)&&(str6!=strr2)) //避免生成分子分母相等的表达式 466 str="("+str5+"/"+strr3+")"+str1[num3]+"("+str6+"/"+strr2+")"; 467 else if(str5==strr3) 468 str=str5+str1[num3]+"("+str6+"/"+strr2+")"; 469 else if(str6==strr2) 470 str="("+str5+"/"+strr3+")"+str1[num3]+str6; 471 n=n-4; 472 while(n!=0) //当n不等于0时,循环生成str,即表达式+符号+表达式的形式 473 { 474 num4=rand()%2; 475 if(num4==0) //上一个str放在符号的左边 476 { 477 sort1(min,max); 478 Simplification(num[4],num[5]); 479 num3=rand()%4; 480 ss5<<num[4]; 481 ss5>>str7; 482 ss6<<num[5]; 483 ss6>>str8; 484 if(str7!=str8) //避免生成分子分母相等的表达式 485 str9="("+str8+"/"+str7+")"; 486 else 487 str9=str8; 488 str=str+str1[num3]+str9; 489 } 490 else //上一个str放在符号的右边 491 { 492 sort1(min,max); 493 Simplification(num[4],num[5]); 494 num3=rand()%4; 495 ss7<<num[4]; 496 ss7>>str7; 497 ss8<<num[5]; 498 ss8>>str8; 499 if(str7!=str8) //避免生成分子分母相等的表达式 500 str9="("+str8+"/"+str7+")"; 501 else 502 str9=str8; 503 str=str9+str1[num3]+str; 504 } 505 n=n-2; 506 } 507 string result1,result2; 508 str4[p]=str; //把str存入字符串数组str4中 509 for(int i=0;i<p;i++) //查询四则运算式是否有重复 510 if(str4[i]==str4[p]) 511 Input2(m,p,min,max,j,q); 512 cout<<str4[p]<<"="; 513 result2=OPeration(str); 514 cin>>result1; 515 if(result1==result2) 516 { 517 cout<<"计算正确"; 518 j++; 519 } 520 else 521 { 522 cout<<"计算错误,答案是"<<setprecision(2)<<fixed<<result2; 523 q++; 524 } 525 outfile<<str4[p]<<endl; 526 cout<<endl; 527 } 528 void ArithMath::changeNum(int n,int y,int min,int max) 529 { 530 int j=0,q=0,num6; 531 if(y==1) 532 { 533 for(int i=0;i<n;i++) 534 { 535 num6=rand()%9+2; 536 switch(num6) 537 { 538 case 2:Input(2,i,min,max,j,q);break; 539 case 3:Input(3,i,min,max,j,q);break; 540 case 4:Input(4,i,min,max,j,q);break; 541 case 5:Input(5,i,min,max,j,q);break; 542 case 6:Input(6,i,min,max,j,q);break; 543 case 7:Input(7,i,min,max,j,q);break; 544 case 8:Input(8,i,min,max,j,q);break; 545 case 9:Input(9,i,min,max,j,q);break; 546 case 10:Input(10,i,min,max,j,q);break; 547 } 548 } 549 cout<<"本次测试结束"<<endl; 550 cout<<"正确----"<<j<<"道题,错误----"<<q<<"道题"<<endl; 551 } 552 else 553 { 554 for(int i=0;i<n;i++) 555 { 556 num6=rand()%9+2; 557 switch(num6) 558 { 559 case 2:Input1(2,i,min,max,j,q);break; 560 case 3:Input1(3,i,min,max,j,q);break; 561 case 4:Input1(4,i,min,max,j,q);break; 562 case 5:Input1(5,i,min,max,j,q);break; 563 case 6:Input1(6,i,min,max,j,q);break; 564 case 7:Input1(7,i,min,max,j,q);break; 565 case 8:Input1(8,i,min,max,j,q);break; 566 case 9:Input1(9,i,min,max,j,q);break; 567 case 10:Input1(10,i,min,max,j,q);break; 568 } 569 } 570 cout<<"本次测试结束"<<endl; 571 cout<<"正确----"<<j<<"道题,错误----"<<q<<"道题"<<endl; 572 573 574 } 575 } 576 void ArithMath::changeNum1(int n,int min,int max) 577 { 578 int j=0,q=0,p,num6; 579 for(int i=0;i<n;i++) 580 { 581 num6=rand()%4; 582 p=4+2*i; //表示生成的操作数的个数 583 switch(p) 584 { 585 case 4:Input2(4,i,min,max,j,q);break; 586 case 6:Input2(6,i,min,max,j,q);break; 587 case 8:Input2(8,i,min,max,j,q);break; 588 case 10:Input2(10,i,min,max,j,q);break; 589 } 590 } 591 cout<<"本次测试结束"<<endl; 592 cout<<"正确----"<<j<<"道题,错误----"<<q<<"道题"<<endl; 593 } 594 void ArithMath::workNum()//控制中心函数 595 { 596 cout<<"**********************欢迎您使用四则运算生成器3.0!**************************"<<endl; 597 int x,y,max,min; 598 srand((unsigned)time(NULL)); 599 ofstream outfile1; 600 outfile1.open("a.txt"); 601 if(!outfile1) 602 { 603 cerr<<"OPEN ERROR!"<<endl; 604 exit(0); 605 } 606 cout<<" 1.整数的四则运算 "<<endl; 607 cout<<" 2.真分数的四则运算 "<<endl; 608 cout<<"请选择:"; 609 cin>>x; 610 while(x!=1&&x!=2) 611 { 612 cout<<"输入有误,请重新输入!"<<endl; 613 cin>>x; 614 } 615 switch(x) 616 { 617 case 1: 618 { 619 cout<<"取值范围最小值(大于等于1):"; 620 cin>>min; 621 cout<<"取值范围最大值:"; 622 cin>>max; 623 cout<<"有(无)括号运算(注释:真分数必须加括号,以防形成6/3/2的形式)---有(1),无(0):"; 624 cin>>y; 625 cout<<"题目数量:"; 626 cin>>n; 627 cout<<" 请开始答题 "<<endl; 628 changeNum(n,y,min,max); 629 break; 630 } 631 case 2: 632 { 633 cout<<"取值分子分母范围最小值(大于等于1):"; 634 cin>>min; 635 cout<<"取值分子分母范围最大值(大于等于1):"; 636 cin>>max; 637 cout<<"题目数量:"; 638 cin>>n; 639 cout<<" 请开始答题 "<<endl; 640 changeNum1(n,min,max); 641 break; 642 } 643 } 644 cout<<"****************************************************************************"<<endl; 645 }
main.cpp
1 #include "ArithMath.h" 2 void main() 3 { 4 int p=1; 5 do 6 { 7 ArithMath s; 8 s.workNum(); 9 cout<<"是否继续生成运算题(输入1则生成否则不生成):"<<endl; 10 cin>>p; 11 while(p!=1&&p!=0) 12 { 13 cout<<"请输入1或0(输入1则生成否则不生成):"<<endl; 14 cin>>p; 15 } 16 }while(p=1); 17 cout<<"The End!"<<endl; 18 }
四、运行结果截图
五、编程总结分析
数据结构和算法真是个好东西啊,以后一定有更多的地方用的到,后悔没有好好学呀,欠下的总得还的,看来得把栈和队列好好补补了
六、时间记录日志
日期 | 开始时间 | 结束时间 | 净时间 | 活动 | 备注 |
3.21 | 8:00,16:00 | 10:00,17:00 | 3h | 上课,编程 | 单元测试 |
3.22 | 19:00 | 20:00 | 1h | 博客 | 读后感 |
3.23 | 19:00 | 20:00 | 1h | 编程 | |
3.24 | 19:00 | 20:00 | 1h | 编程 | |
3.25 | 19:00 | 20:00 | 1h | 编程 | |
3.26 | 9:00,13:00 | 12:30 17:00 | 7.5h | 编程 |