作业要求:
写一个能自动生成小学四则运算题目的命令行 “软件”, 分别满足下面的各种需求,这些需求都可以用命令行参数的形式来指定:
a) 支持整数、真分数的四则运算。例如: 1/6 + 1/8 = 7/24
b) 逐步扩展功能和可以支持的表达式类型,最后希望能支持下面类型的题目(最多 10 个运算符,括号的数量不限制)
25 - 3 * 4 - 2 / 2 + 89 = ?
1/2 + 1/3 - 1/4 = ?
( 5 - 4 ) * ( 3 +28 ) =?
设计思路:
采用使用栈将表达式中缀转后缀的做法,求解表达式的值
对于小数型,采取double型的栈存取,其余做法与一般方法一致
对于分数型,采取字符串的形式进行存取
对于分数型,重载了+,-,*的运算规则,使其满足分数加减乘法的要求。其函数中包含了大量的字符串分割,字符串转整型等操作,最后返回一个结果的字符串
已经实现功能:
- 随机生成整数数或者分数算式,整数算式结果为小数,分数算式结果为真分数
- 真分数的四则运算,结果为真分数
- 支持括号
1 #include <iostream> 2 #include <stdlib.h> 3 #include <time.h> 4 #include <stack> 5 #include <math.h> 6 #include <string.h> 7 #include <iomanip> 8 9 using namespace std; 10 11 char basic_op_de[4]={'+','-','*','/'}; 12 13 unsigned char Prior_de[8][8] ={ // 运算符优先级表 14 // '+' '-' '*' '/' '(' ')' '#' '^' 15 /*+*/'>','>','<','<','<','>','>','<', 16 /*-*/'>','>','<','<','<','>','>','<', 17 /***/'>','>','>','>','<','>','>','<', 18 /*/*/'>','>','>','>','<','>','>','<', 19 /*(*/'<','<','<','<','<','=',' ','<', 20 /*)*/'>','>','>','>',' ','>','>','>', 21 /*#*/'<','<','<','<','<',' ','=','<', 22 /*^*/'>','>','>','>','<','>','>',' ', 23 }; 24 25 char graph_de[8]={'+','-','*','/','(',')','#','^'}; 26 27 28 bool In_de(char a,char b[7]) { //判断是否为运算符 29 int i; 30 bool c=false; 31 for(i=0;i<=7;i++) 32 { 33 if(a==b[i]) 34 c=true; 35 } 36 return c; 37 } 38 39 char Precede_de(char a,char b) {//判断优先级 40 int i,j; 41 if(a=='+') i=0; 42 if(a=='-') i=1; 43 if(a=='*') i=2; 44 if(a=='/') i=3; 45 if(a=='(') i=4; 46 if(a==')') i=5; 47 if(a=='#') i=6; 48 if(a=='^') i=7; 49 if(b=='+') j=0; 50 if(b=='-') j=1; 51 if(b=='*') j=2; 52 if(b=='/') j=3; 53 if(b=='(') j=4; 54 if(b==')') j=5; 55 if(b=='#') j=6; 56 if(b=='^') j=7; 57 return Prior_de[i][j]; 58 } 59 60 double Operate_de(double Num1,char b,double Num2) {//进行运算 61 double result=1; 62 switch(b){ 63 case'+':return Num1+Num2;break; 64 case'-':return Num1-Num2;break; 65 case'*':return Num1*Num2;break; 66 case'/':return Num1/Num2;break; 67 } 68 } 69 70 double EvaluateExpression_de(char* string) //求表达式的值 71 { 72 int count=0; 73 stack<double> p1; //运算数 74 stack<char> p2; 75 stack<double> *S1; 76 stack<char> *S2; //运算符 77 S1=&p1; 78 S2=&p2; 79 char temp,y,x,c,cpre='('; //prec用与记录前一个字符 80 double Num1,Num2,num; 81 char str[50]; 82 str[0]='\0'; 83 int i=0; 84 85 86 temp='#'; 87 S2->push(temp); 88 89 c=string[count]; 90 count++; 91 92 while(c!='#'||S2->top()!='#'){ 93 if(!In_de(c,graph_de)||c=='.') { //是运算数 (含小数点) 94 str[i]=c; 95 i++; 96 cpre=c; 97 c=string[count]; 98 count++; 99 if(In_de(c,graph_de)){ //不是运算数了,则把字符串转化为数字后压栈 100 str[i]='\0'; 101 num=atof(str); 102 S1->push(num); 103 i=0; //字符串初始化 104 str[i]='\0'; 105 } 106 } 107 else{ 108 if(cpre=='('&&c=='-'){ 109 S1->push(0); 110 } 111 switch(Precede_de(S2->top(),c)){ 112 case'<': 113 S2->push(c); //进栈 114 cpre=c; 115 c=string[count]; 116 count++; 117 break; 118 case'=': 119 x=S2->top(); 120 S2->pop(); 121 cpre=c; 122 c=string[count]; 123 count++; 124 break; 125 case'>': 126 y=S2->top(); 127 S2->pop(); 128 Num2=S1->top(); 129 S1->pop(); 130 Num1=S1->top(); 131 S1->pop(); 132 S1->push(Operate_de(Num1,y,Num2));break; //进栈 133 } 134 } 135 } 136 Num1=S1->top(); 137 S1->pop(); 138 return Num1; 139 } 140 141 char basic_op[3]={'+','-','*'}; 142 143 144 unsigned char Prior[6][6] ={ // 运算符优先级表 145 // '+' '-' '*' '(' ')' '#' 146 /*+*/'>','>','<','<','>','>', 147 /*-*/'>','>','<','<','>','>', 148 /***/'>','>','>','<','>','>', 149 /*(*/'<','<','<','<','=',' ', 150 /*)*/'>','>','>','>','>','>', 151 /*#*/'<','<','<','<',' ','=', 152 }; 153 154 char graph[6]={'+','-','*','(',')','#'}; 155 156 bool In(char a,char b[6]) { //判断是否为运算符 157 int i; 158 bool c=false; 159 for(i=0;i<=5;i++) 160 { 161 if(a==b[i]) 162 c=true; 163 } 164 return c; 165 } 166 167 char Precede(char a,char b) { //判断优先级 168 int i,j; 169 if(a=='+') i=0; 170 if(a=='-') i=1; 171 if(a=='*') i=2; 172 if(a=='(') i=3; 173 if(a==')') i=4; 174 if(a=='#') i=5; 175 if(b=='+') j=0; 176 if(b=='-') j=1; 177 if(b=='*') j=2; 178 if(b=='(') j=3; 179 if(b==')') j=4; 180 if(b=='#') j=5; 181 return Prior[i][j]; 182 } 183 int HCF(int n,int m) {//最大公约数 184 int p,r,temp; 185 if (n<m) { 186 temp=n; 187 n=m; 188 m=temp; //把大数放在n中, 小数放在m中 189 } 190 p=n*m; //先将n和m的乘积保存在p中, 以便求最小公倍数时用 191 while (m!=0){ //求n和m的最大公约数 192 r=n%m; 193 n=m; 194 m=r; 195 } 196 return n; 197 } 198 199 int LCD(int n,int m) { //最小公倍数 200 int p,r,temp; 201 if (n<m){ 202 temp=n; 203 n=m; 204 m=temp; //把大数放在n中, 小数放在m中 205 } 206 p=n*m; //先将n和m的乘积保存在p中, 以便求最小公倍数时用 207 while (m!=0) //求n和m的最大公约数 208 {r=n%m; 209 n=m; 210 m=r; 211 } 212 return p/n; 213 } 214 char *yuefen(int l,int r) { //约分 215 char *left=(char*)malloc(sizeof(char)*200); 216 char *right=(char*)malloc(sizeof(char)*200); 217 char *temp_result2=(char*)malloc(sizeof(char)*1000); 218 if(HCF(l,r)!=1){//不互质 219 int k=HCF(l,r); 220 l=l/k; 221 r=r/k; 222 } 223 itoa(l,left,10); 224 itoa(r,right,10); 225 strcpy(temp_result2,left); 226 strcat(temp_result2,"/"); 227 strcat(temp_result2,right); 228 229 230 return temp_result2; 231 } 232 233 char * Operate(char* Num1,char b,char* Num2){ //进行运算 234 int num1_l,num1_r,num2_l,num2_r,num3_l,num3_r; 235 char *Num1_left=(char*)malloc(sizeof(char)*200); 236 char *Num1_right=(char*)malloc(sizeof(char)*200); 237 char *Num2_left=(char*)malloc(sizeof(char)*200); 238 char *Num2_right=(char*)malloc(sizeof(char)*200); 239 char *temp_result1=(char*)malloc(sizeof(char)*1000); 240 241 int i=0,j; //分割字符串为4个数 242 for(i=0;Num1[i]!='/';i++){ 243 Num1_left[i]=Num1[i]; 244 } 245 Num1_left[i]='\0'; 246 j=i; 247 for(i=0;;i++){ 248 Num1_right[i]=Num1[i+j+1]; 249 if(Num1_right[i]=='\0') 250 break; 251 } 252 for(i=0;Num2[i]!='/';i++){ 253 Num2_left[i]=Num2[i]; 254 } 255 Num2_left[i]='\0'; 256 j=i; 257 for(i=0;;i++){ 258 Num2_right[i]=Num2[i+j+1]; 259 if(Num2_right[i]=='\0') 260 break; 261 } 262 263 num1_l=atoi(Num1_left); //字符串转整型数字 264 num1_r=atoi(Num1_right); 265 num2_l=atoi(Num2_left); 266 num2_r=atoi(Num2_right); 267 268 switch(b){ 269 case'+': 270 if(num1_r==num2_r){ //同分母 271 num1_l=num1_l+num2_l; 272 strcpy(temp_result1,yuefen(num1_l,num1_r)); 273 } 274 else{ //分母不同 275 num3_r=LCD(num1_r,num2_r); //通分后的分母 276 num1_l=num1_l*num3_r/num1_r; 277 num2_l=num2_l*num3_r/num2_r; 278 num3_l=num1_l+num2_l; //通分之后的分子 279 strcpy(temp_result1,yuefen(num3_l,num3_r)); 280 } 281 break; 282 283 case'-': 284 if(num1_r==num2_r){ //同分母 285 num1_l=num1_l-num2_l; 286 strcpy(temp_result1,yuefen(num1_l,num1_r)); 287 } 288 else{ //分母不同 289 num3_r=LCD(num1_r,num2_r); //通分后的分母 290 num1_l=num1_l*num3_r/num1_r; 291 num2_l=num2_l*num3_r/num2_r; 292 num3_l=num1_l-num2_l; //通分之后的分子 293 strcpy(temp_result1,yuefen(num3_l,num3_r)); 294 } 295 break; 296 case'*': 297 num3_r=num1_r*num2_r; 298 num3_l=num1_l*num2_l; 299 strcpy(temp_result1,yuefen(num3_l,num3_r)); 300 break; 301 } 302 303 return temp_result1; 304 } 305 306 char* EvaluateExpression(char* string){ //求表达式的值 307 int str_counter; 308 char **str= (char**)malloc(sizeof(char*)*20); //存储运算数的字符串载体 309 for(str_counter=0; str_counter<20; str_counter++) { 310 str[str_counter] = (char*)malloc(sizeof(char)*200); 311 str[str_counter][0]='\0'; //初始化 312 } 313 str_counter=0; 314 315 int temp_result_counter; 316 char ** temp_result=(char**)malloc(sizeof(char)*20); //作为中间运算结果的载体 317 for(temp_result_counter=0; temp_result_counter<20; temp_result_counter++) { 318 temp_result[temp_result_counter] = (char*)malloc(sizeof(char)*1000); 319 temp_result[temp_result_counter][0]='\0'; //初始化 320 } 321 temp_result_counter=0; 322 323 int count=0; 324 stack<char *> p1; //运算数 325 stack<char> p2; 326 stack<char *> *S1; 327 stack<char> *S2; //运算符 328 S1=&p1; 329 S2=&p2; 330 char temp,y,x,c,cpre='('; //cpre用于记录前一个字符 331 char * Num1=(char*)malloc(sizeof(char)*200); 332 char * Num2=(char*)malloc(sizeof(char)*200); 333 334 int i=0; 335 336 temp='#'; 337 S2->push(temp); 338 339 c=string[count]; 340 count++; 341 342 while(c!='#'||S2->top()!='#'){ 343 if(!In(c,graph)) //是运算数 (含小数点) 344 { 345 str[str_counter][i]=c; 346 i++; 347 cpre=c; 348 c=string[count]; 349 count++; 350 if(In(c,graph)){ //不是运算数了,则把字符串转化为数字后压栈 351 str[str_counter][i]='\0'; 352 S1->push(str[str_counter]); //压栈的不是内容,是地址 353 str_counter++; 354 i=0; 355 } 356 } 357 else{ //运算符 358 359 switch(Precede(S2->top(),c)){ 360 case'<': 361 S2->push(c); //进栈 362 cpre=c; 363 c=string[count]; 364 count++; 365 break; 366 case'=': 367 x=S2->top(); 368 S2->pop(); 369 cpre=c; 370 c=string[count]; 371 count++; 372 break; 373 case'>': 374 y=S2->top(); 375 S2->pop(); 376 strcpy(Num2,S1->top()); 377 S1->pop(); 378 strcpy(Num1,S1->top()); 379 S1->pop(); 380 strcpy(temp_result[temp_result_counter],Operate(Num1,y,Num2)); //修改中间结果 381 S1->push(temp_result[temp_result_counter]); 382 temp_result_counter++; 383 break; 384 } 385 } 386 } 387 strcpy(Num1,S1->top()); 388 S1->pop(); 389 return Num1; 390 } 391 392 393 int main() 394 { 395 int swi; 396 cout<<"-----------欢迎使用小学生计算器---------\n"<<endl; 397 cout<<"--------------输入1;小数计算---------\n"<<endl; 398 cout<<"--------------输入2;分数计算---------\n"<<endl; 399 cout<<"--------------输入0;退出---------\n"<<endl; 400 401 cout<<"你的选择:"; 402 cin>>swi; 403 if(swi==0) return 0; 404 else if(swi==1){ 405 int count ,left ,right ,op_num,LR,temp; 406 double result; 407 double stu_answer; 408 409 char *op=(char *)malloc(sizeof(char)*3); 410 char *left_string=(char *)malloc(sizeof(char)*200); 411 char *temp_string=(char *)malloc(sizeof(char)*1000); 412 413 srand(time(0)); 414 temp=rand()%20+1; 415 itoa(temp,temp_string,10); 416 417 for(count=1;count<=5;count++){ 418 419 op_num=rand()%4; 420 op[0]=basic_op_de[op_num]; 421 op[1]='\0'; 422 LR=rand()%2; 423 if(LR==0){ //上一步的表达式在左侧 424 425 left=rand()%20+1; 426 itoa(left,left_string,10); 427 strcat(temp_string,op); 428 strcat(temp_string,left_string); 429 } 430 else{ //上一步的表达式在右侧 431 432 433 left=rand()%20+1; 434 itoa(left,left_string,10); 435 strcat(left_string,op); 436 strcat(left_string,temp_string); 437 strcpy(temp_string,left_string); 438 } 439 LR=rand()%5; 440 if(LR<=1){ //加括号 441 442 char zuokuohao[200]="(",youkuohao[4]=")"; 443 strcat(zuokuohao,temp_string); 444 strcat(zuokuohao,youkuohao); 445 strcpy(temp_string,zuokuohao) ; 446 } 447 448 } 449 450 cout<<"题目是:"<<temp_string<<endl<<endl; 451 452 strcat(temp_string,"#"); 453 454 result=EvaluateExpression_de(temp_string); 455 456 cout<<"请输入你的答案:(保留两位小数) "; 457 cin>>stu_answer; 458 cout<<endl<<"正确答案为: "<<setprecision(2) <<std::fixed<<result<<endl<<endl; 459 if(result==stu_answer) 460 cout<<"恭喜你,答对了"<<endl<<endl; 461 else 462 cout<<"答错了,没关系,这道题有点难"<<endl<<endl; 463 464 465 } 466 if(swi==2){ 467 int count ,left ,right ,op_num,LR,temp; 468 469 char *op=(char *)malloc(sizeof(char)*3); 470 char *left_string=(char *)malloc(sizeof(char)*200); 471 char *right_string=(char *)malloc(sizeof(char)*200); 472 char *temp_string=(char *)malloc(sizeof(char)*1000); 473 char *temp_string_right=(char *)malloc(sizeof(char)*200); 474 char *result=(char *)malloc(sizeof(char)*1000); 475 476 char stu_answer[100]; 477 478 srand(time(0)); 479 temp=rand()%20+1; 480 itoa(temp,temp_string,10); 481 strcat(temp_string,"/"); 482 temp=rand()%50+1; 483 itoa(temp,temp_string_right,10); 484 strcat(temp_string,temp_string_right); 485 486 for(count=1;count<=5;count++){ 487 488 489 op_num=rand()%3; 490 op[0]=basic_op[op_num]; 491 op[1]='\0'; 492 LR=rand()%2; 493 if(LR==0){ //上一步的表达式在左侧 494 495 right=rand()%50+1; 496 itoa(right,right_string,10); 497 left=rand()%20+1; 498 itoa(left,left_string,10); 499 strcat(temp_string,op); 500 strcat(temp_string,left_string); 501 strcat(temp_string,"/"); 502 strcat(temp_string,right_string); 503 } 504 else{ //上一步的表达式在右侧 505 506 right=rand()%50+1; 507 itoa(right,right_string,10); 508 left=rand()%20+1; 509 itoa(left,left_string,10); 510 strcat(left_string,"/"); 511 strcat(left_string,right_string); 512 strcat(left_string,op); 513 strcat(left_string,temp_string); 514 strcpy(temp_string,left_string); 515 } 516 LR=rand()%5; 517 if(LR<=1){ //加括号 518 519 char zuokuohao[200]="(",youkuohao[4]=")"; 520 strcat(zuokuohao,temp_string); 521 strcat(zuokuohao,youkuohao); 522 strcpy(temp_string,zuokuohao) ; 523 } 524 525 } 526 cout<<"题目是:"<<temp_string<<endl<<endl; 527 528 strcat(temp_string,"#"); 529 530 strcpy(result,EvaluateExpression(temp_string)); 531 532 cout<<"请输入你的答案: "; 533 cin>>stu_answer; 534 cout<<endl<<"正确答案为: "<<result<<endl<<endl; 535 if(strcmp(result,stu_answer)==0) 536 cout<<"恭喜你,答对了"<<endl<<endl; 537 else 538 cout<<"答错了,没关系,这道题超纲了"<<endl<<endl; 539 } 540 541 }
运行截图:
结果为小数
结果为分数
github仓库路径:https://github.com/DJJune/calculator