首页 > 技术文章 > 四则运算3

cnyulei 2016-03-19 09:17 原文

      第一次真正意义上的结对编程,感觉还需要磨合。我们拿到这个题目,首先主要是对四则运算2的计算结果进行编程,在可以生成算式的结果上进行编程。我们考虑到用栈来实现表达式求值。首先将栈的一些函数进行编写,比如,出栈入栈函数,获取栈顶元素函数。然后给+、-、*、/、(、)、#列一个优先级表,根据表达式求值的算法。

      1.建立并初始化OPTR和OPND栈,分别存放符号和数字。

      2.依次取表达式的每个值和符号,执行3-5,知道求出最后的值。

      3.去除optr栈顶元素,与都入的进行比较,当读入#时,求解完毕。

      4.栈顶元素是数字,压opnd栈

      5.如果是符号,将符号与optr栈顶元素进行比较,如果小于,将符号压入optr,如果大于,optr出栈,做相应运算,然后将计算结果压入opnd栈,如果等于,optr栈顶元素为(,读入字符为),这时候optr出栈,继续读取下一个字符。

      根据这个算法,我们也遇到了很多问题:

      第一,我们将其调试,成功的第一步是能够运算10以内的四则运算,但是若两位数呢。

      第二,我们将程序进行改进,把char类型换为double类型,然后建立了三个数组,double a[],char b[],int clu[],分别存放操作数,运算符和对应位置应该是什么(clu[0]=1,表示第一个应该是一个数,clu[1]=2,表示此时应该为一个符号),这样就能是操作数不再局限于一位数了。

      第三,程序可以了以后,我们又将程序编程一个字符串,将字符串分开存到三个数组里,在进行运算。根据clu数组的值,在数组a[],b[]进行取值,并运算。

程序代码:

  1 /*
  2 结对编程《四则运算》
  3 于磊  20133078
  4 李萌  20133079 */
  5 #include <iostream>
  6 #include <string>
  7 #include <ctime>
  8 #define N 50
  9 using namespace std;
 10 void Operands_1()  /*产生操作数 (-9 -- 9)除0*/
 11 {
 12     while(int f=1)  
 13     {
 14         int Oper=rand()%19-9;
 15         if(Oper>0)             /*没有0*/
 16         {
 17             cout<<Oper;
 18             break;
 19         }
 20         if(Oper<0)
 21         {
 22             cout<<"("<<Oper<<")";
 23             break;
 24         }
 25     }
 26 }
 27 void Operands_2()/*-9到9  有0*/
 28 {
 29     while(int f=1)  /*产生操作数 (-9 -- 9)*/
 30     {
 31         int Oper=rand()%19-9;
 32         if(Oper>=0)/*有0*/
 33         {
 34             cout<<Oper;
 35             break;
 36         }
 37         else
 38         {
 39             cout<<"("<<Oper<<")";
 40             break;
 41         }
 42     }
 43 }
 44 int Operands_3() /*0-9*/
 45 {
 46     int Operand=rand()%9+1;
 47     return Operand;
 48 }
 49 string Operands_4()
 50 {
 51     string s="";
 52     int Operand=rand()%99+1;
 53     if(Operand<10)
 54     {
 55         s+=Operand+48;
 56     }
 57     else
 58     {
 59         s+=Operand/10+48;
 60         s+=Operand%10+48;
 61     }
 62     return s;
 63 }
 64 void Operator_1(string &formula)/*随机产生运算符   有乘除*/
 65 {
 66     int f=rand()%4;
 67     if(f==0) 
 68     {
 69         formula+="+";
 70     }
 71     if(f==1)
 72     {
 73         formula+="-";
 74     }
 75     if(f==2)
 76     {
 77         formula+="*";
 78     }
 79     if(f==3)
 80     {
 81         formula+="/";
 82     }
 83 }
 84 void Operator_2(string &formula)/*随机产生运算符   无乘除*/
 85 {
 86     int f=rand()%2;
 87     if(f==0) 
 88     {
 89         formula+="+";
 90     }
 91     if(f==1)
 92     {
 93         formula+="-";
 94     }
 95 }
 96 int Bracket_l(int left,string &formula) /*随机产生左括号*/
 97 {
 98     int f=rand()%3;
 99     if(f<2)
100     {
101         return left;
102     }
103     if(f==2)
104     {
105         formula+="(";
106         return left+1;
107     }
108     return 0;
109 }
110 int Bracket_r(int right,string &formula) /*随机产生右括号*/
111 {
112     int r=rand()%5;
113     if(r==0)
114     {
115         return right;
116     }
117     if(r>0) /*产生右括号的概率大 */
118     {
119         formula+=")";
120         return right+1;
121     }
122     return 0;
123 }
124 string Way_1() /*最多可支持10个数参与计算   有乘除 有括号 10以内 加减有负数 除法有余数*/
125 {
126     string formula="";
127     int length=rand()%9+2; /*随机产生表达式中操作数的个数 2-10 个*/
128     int left=0,right=0,flag=0,left_1;
129     for(int i=0;i<length-1;i++)
130     {
131         left_1=left;
132         left=Bracket_l(left,formula);
133         if(left_1!=left)     /*产生了左括号  flag=i*/
134         {
135             flag=i;
136         }
137         //cout<<Operands_3();
138         formula+=Operands_4();
139         if(left>right&&flag!=i) /*左括号大于右括号的个数 and 产生左括号和右括号不在一个循环里  即不会产生“(随机数)” 这种无效情况*/
140         {
141             right=Bracket_r(right,formula);
142         }
143         Operator_1(formula);  /*有乘除*/
144     }
145    // cout<<Operands_3(); /*因为 一个操作数一个运算符   还缺少一个操作数 (0 -- 9)*/
146     formula+=Operands_4();
147     for(int i=0;i<left-right;i++)
148     {
149         //cout<<")";
150         formula+=")";
151     }
152    // cout<<" = "<<endl;
153     return formula+="#";
154 }
155 
156 string Way_2() /*最多可支持10个数参与计算   没乘除 有括号 10以内 加减有负数 除法有余数*/
157 {
158     string formula="";
159     int length=rand()%9+2; /*随机产生表达式中操作数的个数 2-10 个*/
160     int left=0,right=0,flag=0,left_1;
161     for(int i=0;i<length-1;i++)
162     {
163         left_1=left;
164         left=Bracket_l(left,formula);
165         if(left_1!=left)     /*产生了左括号  flag=i*/
166         {
167             flag=i;
168         }
169         //cout<<Operands_3();
170         formula+=Operands_4();
171         if(left>right&&flag!=i) /*左括号大于右括号的个数 and 产生左括号和右括号不在一个循环里  即不会产生“(随机数)” 这种无效情况*/
172         {
173             right=Bracket_r(right,formula);
174         }
175         Operator_2(formula);  /*有乘除*/
176     }
177    // cout<<Operands_3(); /*因为 一个操作数一个运算符   还缺少一个操作数 (0 -- 9)*/
178     formula+=Operands_4();
179     for(int i=0;i<left-right;i++)
180     {
181         formula+=")";
182     }
183     return formula+="#";
184 }
185 string Way_3() /*最多可支持10个数参与计算   没乘除 有括号 10以内 加减有负数 除法有余数*/
186 {
187     string formula="";
188     int length=rand()%9+2; /*随机产生表达式中操作数的个数 2-10 个*/
189     int left=0,right=0,flag=0;
190     for(int i=0;i<length-1;i++)
191     {
192         formula+=Operands_4();
193         Operator_1(formula);  /*有乘除*/
194     }
195    // 因为 一个操作数一个运算符   还缺少一个操作数 (0 -- 9)*/
196     formula+=Operands_4();
197     return formula+="#";
198 }
199 string Way_4() /*最多可支持10个数参与计算   没乘除 没括号 10以内 加减有负数 除法有余数*/
200 {
201     string formula="";
202     int length=rand()%9+2; /*随机产生表达式中操作数的个数 2-10 个*/
203     int left=0,right=0,flag=0;
204     for(int i=0;i<length-1;i++)
205     {
206         formula+=Operands_4();
207         Operator_2(formula);  /*有乘除*/
208     }
209    // 因为 一个操作数一个运算符   还缺少一个操作数 (0 -- 9)*/
210     formula+=Operands_4();
211     return formula+="#";
212 }
213 //*****************************************************************************
214 double jisuan(double x,double y,char oper)
215 { 
216     switch(oper)
217     {
218     case '+':
219         {
220             return x+y;
221             break;
222         } 
223     case '-':
224         {
225             return x-y;
226             break;
227         }
228     case '*':
229         {
230             return x*y;
231             break;
232         } 
233     case '/':
234         {
235             return x/y;
236             break;
237         }  
238     }
239     return 0;
240 }
241 
242 typedef struct{
243     double *base;
244     double *top;
245     int stacksize;
246 }SqStack;
247 //初始化化栈
248 double InitStack(SqStack &S)
249 {
250     S.base=new double[N];
251     if(!S.base)
252         exit(0);
253     S.top=S.base;
254     S.stacksize=N;
255     return 1;
256 }
257 
258 //入栈操作代码
259 char push(SqStack &S,char s)
260 {
261     if(S.top-S.base==S.stacksize)
262         return 0;
263     *S.top=s;
264     S.top++;
265     return s;
266 }
267 
268 double push1(SqStack &S,double s)
269 {
270     if(S.top-S.base==S.stacksize)
271         return 0;
272     *S.top=s;
273     S.top++;
274     return s;
275 }
276 //出栈操作代码
277 char pop(SqStack &S)
278 {
279     char x;
280     if(S.top==S.base)
281         return 0;
282     --S.top;
283     x=*S.top;
284     return x;
285 }
286 
287 double pop1(SqStack &S)
288 {
289     double x;
290     if(S.top==S.base)
291         return 0;
292     --S.top;
293     x=*S.top;
294     return x;
295 }
296 //取栈顶元素
297 double GetTop(SqStack S)
298 {
299     if(S.top==S.base)
300         exit(1);
301     return *(S.top-1);
302 }
303 
304 char precede(char ch1,char ch2)
305 {
306     int i,j;
307     char a[7][7]={        //优先级对照表,依次为+ - * / ( ) #
308         //  +   -   *   /   (   )   #
309         '>','>','<','<','<','>','>',    // +
310         '>','>','<','<','<','>','>',    // - 
311         '>','>','>','>','<','>','>',    // * 
312         '>','>','>','>','<','>','>',    // /
313         '<','<','<','<','<','=','0',    // (
314         '>','>','>','>','0','>','>',    //
315         '<','<','<','<','<','0','='     // #
316     };
317     switch(ch1)
318     {
319         //优先级与矩阵匹配
320     case '+':
321         {
322             i=0;
323             break;
324         }
325     case '-':
326         {
327             i=1;
328             break;
329         }
330     case '*':
331         {
332             i=2;
333             break;
334         }
335     case '/':
336         {
337             i=3;
338             break;
339         }
340     case '(':
341         {
342             i=4;
343             break;
344         }
345     case ')':
346         {
347             i=5;
348             break;
349         }
350     case '#':
351         {
352             i=6;
353             break;
354         }
355     }
356     switch(ch2)
357     {
358         //优先级与矩阵匹配
359     case '+':
360         {
361             j=0;
362             break;
363         }
364     case '-':
365         {
366             j=1;
367             break;
368         }
369     case '*':
370         {
371             j=2;
372             break;
373         }
374     case '/':
375         {
376             j=3;
377             break;
378         }
379     case '(':
380         {
381             j=4;
382             break;
383         }
384     case ')':
385         {
386             j=5;
387             break;
388         }
389     case '#':
390         {
391             j=6;
392             break;
393         }
394     }
395     return a[i][j];
396 }
397 
398 double calculate(string str)
399 {
400     int i=0,j=0,k=0,w=0;
401     int s=str.length();
402     double a[N]={0};
403     char b[N]={0};
404     int clu[N]={0};
405     for(k=0;k<s;)
406     {
407         if(str[k]>='0'&&str[k]<='9')
408         {
409             while(str[k]>='0'&&str[k]<='9')
410             {
411                 a[i]=(a[i])*10+(str[k]-48);
412                 k++;
413             }
414             i++;
415             clu[w]=1;
416             w++;
417         }
418         else
419         {
420             b[i]=str[k];
421             k++;
422             i++;
423             clu[w]=2;
424             w++;
425         }
426     }
427     double result;
428     i=0;
429     SqStack optr,opnd;
430     InitStack(optr);
431     push(optr,'#');
432     InitStack(opnd);
433     push(opnd,'#');
434     while(clu[i]!=0&&b[i]!='#'||GetTop(optr)!='#'&&i<s)
435     {
436         if(clu[i]==1)
437         {
438             push1(opnd,a[i]);
439             //cin>>ch;
440             i++;
441         }
442         else
443             switch(precede(GetTop(optr),b[i])){
444             case '<':
445                 {
446                     push(optr,b[i]);
447                     i++;
448                     break;
449                 }
450             case '>':
451                 {
452                     double y=pop1(opnd);
453                     double x=pop1(opnd);
454                     char ch=pop(optr);
455                     result=jisuan(x,y,ch);
456                     push1(opnd,result);
457                     break;
458                 }
459             case '=':
460                 {
461                     pop(optr);
462                     i++;
463                     break;
464                 }
465         }
466     }
467     return result;
468 }
469 //********************************************************
470 int main() /*主函数*/
471 {
472     srand((unsigned)time(0));
473     int number=0,a,b;
474     cout<<"------------------------------四则运算---------------------------------"<<endl;
475     cout<<"是否有乘除:是1否0:";
476     cin>>a;
477     while(a!=0&&a!=1)
478     {
479         cout<<"输入有误!!!请重新输入:";
480         cin>>a;
481     }
482     cout<<"是否有括号:是1否0:";
483     cin>>b;
484     while(b!=0&&b!=1)
485     {
486         cout<<"输入有误!!!请重新输入:";
487         cin>>b;
488     }
489     if(a==1&&b==1)
490         cout<<"最多可支持10个数参与计算  有乘除 有括号 100以内  加减有负数 除法有余数"<<endl;
491     if(a==0&&b==1)
492         cout<<"最多可支持10个数参与计算  无乘除 有括号 100以内  加减有负数 除法有余数"<<endl;
493     if(a==1&&b==0)
494         cout<<"最多可支持10个数参与计算  有乘除 无括号 100以内  加减有负数 除法有余数"<<endl;
495     if(a==0&&b==0)
496         cout<<"最多可支持10个数参与计算  无乘除 无括号 100以内  加减有负数 除法有余数"<<endl;
497     cout<<"-----------------------------------------------------------------------"<<endl;
498     cout<<"请输入题目的数量:";
499     int nu;
500     cin>>nu;
501     for(int num=0;num<nu;num++)
502     {
503         string s;
504         if(a==1&&b==1)
505         {
506             cout<<num+1<<"";
507             s=Way_1();
508         }
509         if(a==0&&b==1)
510         {
511             cout<<num+1<<"";
512             s=Way_2();
513         }
514         if(a==1&&b==0)
515         {
516             cout<<num+1<<"";
517             s=Way_3();
518         }
519         if(a==0&&b==0)
520         {
521             cout<<num+1<<"";
522             s=Way_4();
523         }
524         for(int i=0;i<s.length()-1;i++)
525         {
526             cout<<s[i];
527         }
528         cout<<"=";
529         double a;
530         cin>>a;
531         if(a==calculate(s))
532         {
533             cout<<"---恭喜你!回答正确!"<<endl;
534             number++;
535         }
536         else
537         {
538             cout<<"---很遗憾!回答错误!正确答案为:"<<calculate(s)<<endl;
539         }
540     }
541     cout<<"-----------------------------------------------------------------------"<<endl;
542     cout<<"\t\t您一共做对了"<<number<<"道题! 所得分数为__"<<100/nu*number<<"分__"<<endl;
543     cout<<endl;
544     return 0;
545 }

运行结果:

无括号,无乘除:

有括号,有乘除:

无乘除,有括号:

     实验结果表明,要想做对一道这样的四则运算,必须要有耐心和勇气,并且带有乘除的无法保证其整出,算对带有出发的只能靠运气,有待优化。

     项目计划总结:

日期\任务 听课 编写程序 查阅资料 日总计
星期一 2   1 3
星期二   2   2
星期三   5   5
星期四 2    1 3
星期五   3   3
星期六   4   4
星期日        
周总计 4 14 2

20

      时间记录日志:

日期 开始 结束 中断 总时间 具体活动 备注
3/14 14:00 15:50 30 110 听课 软件工程
  16:00 17:00 无中断 60 查阅数据结构资料 查资料
3/15 16:10 18:10 10 110 编写程序 栈的基本操作编写
3/16 15:10 16:10 无中断 80 编程序 char类型输入,10以内运算
  18:00 19:10 无中断 70 编写程序 将产生式子与计算结果的代码结合,完成正误判断
  19:30 22:30 30 150 编写程序 修复char与int之间的转换bug
3/17 14:00 15:50 10 100 听课 软件工程
3/18 19:00 23:30 30 240 编程序  char->double转换,完成多位数的计算
3/19 7:30 9:40 10 120 代码整合,找bug  
  9:40 10:40 60 1040min 调试+博客 写博客

    

       缺陷记录日志:

日期 编号 引入阶段 排除阶段 修复时间&问题描述
3/14        
3/15  1 编码 编译 栈的操作返回值类型出现问题,将其转换为char
3/16  2 编码 编译 修复char与int之间的转换bug
3/17  3 编码 编译 char->double转换,修复小数的bug
3/18  4 编码 编译 只能一位数的运算,添加了三个数组,解决这个bug
3/19  4 调试 修复 解决用户输入问题,然后判断正误

     我们的结对照片:    

     小伙伴的博客链接:http://www.cnblogs.com/L-Damon-v/

推荐阅读