zoukankan      html  css  js  c++  java
  • 博客二记之四则运算

    运算进化

      在博客一记中,随机生成小学30道带有判断功能的加减法,根据需求的变化,在这一记中将有新的需求。不只是简单的加减法,而是要生成四则运算。根据有关资料表明四则运算要有三个及以上的运算符,只有这样的式子运算才能称的上是四则运算。

    • 第一步:继承博客一记中的思想也是将题用一个类表示。相对于博客一记中的类,新的类明显要复杂得多。不只是有两个操作数,一个运算符,必须要有一段空间来保存操作数和运算符。因为要随机生成操作数及运算符,操作数的个数也是不确定的,故采用动态内存分配的方式。
    class Problem
    {
    private:
        int *Operand;//存放操作数
        int *Type;//存放运算符,0+  ,1-  ,2*  ,3/   
        string *Prob;//存放完整的问题
    
        int opnum;//操作数个数
        int brackets[2];//括号的位置
    
        int Right_Result;//正确结果
        int Write_Result;//填写的结果
    public:
        Problem();
        ~Problem();
        void CreatProblem(int kuohao = 1);//创建题目
        void SaveProblem();//将题目保存到Prob[]
        void ShowProblem();//显示题目
        void Fill_Result();//填写结果
        void Judge_Result();//判断结果
    
    };
    • 第二步,类的创建。将所有的操作数都放在了一个整型数组里,将所有的运算符也都放在数组里,最后形成的问题放到string类数组里。根据实际情况,预先设定宏定
      # define OPERAND_NUM 4 //操作数不小于3,小于3+OPERAND_NUM
    
    
    Problem::Problem()
    {
        opnum = 3+rand()%OPERAND_NUM;//操作数不小于3,小于3+OPERAND_NUM
        Operand = new int[opnum];
    
        Type = new int[opnum-1];
        Prob = new string[3*opnum];
        for(int t = 0;t<3*opnum;t++)
        {
            Prob[t] = "";
        
        
        }
    
    
    }
    
    
    
     

    第三步,公有成员函数void CreatProblem()的设计。该函数用于问题的生成,有无括号有参数括号的值决定,默认为1,有括号。

    
    
    void Problem::CreatProblem(int kuohao)
    {
        
        for(int i = 0;i<opnum-1;i++)//生成少一个的操作数、生成运算符
        {
            
            Operand[i] = rand()%100;
            Type[i] = rand()%4;
            if(Type[i] == 3&&Operand[i] == 0)//排除除数为0的可能
            {
                
                while(Operand[i] == 0)
                {
                    Operand[i] = rand()%100;
                }
            
            }
    
        }
        Operand[opnum-1] = rand()%100;//生成最后一个操作数
        
        if(kuohao == 1)//有括号
        {
        brackets[0] = rand()%(opnum -1);
        brackets[1] = brackets[0] + 1 + rand()%(opnum -1-brackets[0]);//不在第一个括号的位置且不超过
        }
        else//无括号
        {
        brackets[0] = -1;
        brackets[1] = -1;
        }
     
    }
    
    
    
     
    • 第四步,公有成员函数void SaveProblem()的设计。该函数用于问题的保存。
    1. 如何选择保存问题的结构一开始时纠结了好一段时间。

      首先想到的是直接用字符串来保存,可是当要进行计算结果时,用字符串保存明显为后续的递归下降分析来计算结果带来新的问题——区分数字,也就不好办了。也就否决了用字符串来保存问题。

      突然想到c++有string这个标准类,是字符串类,动态申请内存,能够保存多个字符串,保证了Prob里能保证数字不再是单个数而是一串数,也就不用判断组合成数字。 

      2. 如何设计算法将问题保存到结构里。

          前opnum-1个操作数与运算符是成对出现的,而左括号只能出现在操作数前面,右括号只能出现在操作数的后面。在循环进行判断之前声明变量num来记录当前数组的下标。每有成员写入Prob里就将num加1。

    void Problem::SaveProblem()
    {
        int num = 0;//string数组的下标
        for(int temp =0;temp<opnum-1;temp++)
        {
            char str[10];
            sprintf(str,"%d",Operand[temp]);//将整型转换成字符串
            switch(Type[temp])
            {
                /********case后的循环是去除除数为0的可能*********/
            case 0:
                {
                    while((Type[temp-1]==3)&&(Operand[temp]==0))
                    {
                        srand(time(0));
                        Operand[temp] = rand()%100; 
                    }
                    if(temp == brackets[0])
                    {        
                        Prob[num] = "(";
                        num++;
                        //strcat(tempprob,"(");          
                    }  
                    Prob[num] = str;
                    num++;
                    //strcat(tempprob,str);
                    
                    if(temp == brackets[1])
                    {            
                        Prob[num] = ")";
                        num++;
                        //strcat(tempprob,")");
                
                    }
                    
                    Prob[num] = " + ";
                    num++;
                    //strcat(tempprob," + ");
                    break;
                }
            
            case 1:
                {
                    while((Type[temp-1]==3)&&(Operand[temp]==0))
                    {
                        srand(time(0));
                        Operand[temp] = rand()%100;
                   }
                    if(temp == brackets[0])
                    {
                        Prob[num] = "(";
                        num++;
                        //strcat(tempprob,"(");      
                    }  
                    Prob[num] = str;
                    num++;
                    //strcat(tempprob,str);
                    
                    if(temp == brackets[1])
                    {
                    
                        Prob[num] = ")";
                        num++;
                        //strcat(tempprob,")");            
                    }
            
                    Prob[num] = " - ";
                    num++;
                    //strcat(tempprob," - ");
                    break;
                }
            
            case 2:
                {
                    while((Type[temp-1]==3)&&(Operand[temp]==0))
                    {
                        srand(time(0));
                        Operand[temp] = rand()%100;             
                    }
                    if(temp == brackets[0])
                    {         
                        Prob[num] = "(";
                        num++;
                        //strcat(tempprob,"(");
                 
                    }
                    Prob[num] = str;
                    num++;
                    //strcat(tempprob,str);
                    
                    if(temp == brackets[1])
                    {
                
                        Prob[num] = ")";
                        num++;
                        //strcat(tempprob,")");
                  
                    }
    
                    Prob[num] = " * ";
                    num++;
                    //strcat(tempprob," + ");
                    break;
                }
            
            case 3:
                {
                    while((Type[temp-1]==3)&&(Operand[temp]==0))
                    {
                        srand(time(0));
                        Operand[temp] = rand()%100;             
                    }
                    if(temp == brackets[0])
                    {   
                        Prob[num] = "(";
                        num++;
                        //strcat(tempprob,"(");
               
                    }
          
                    Prob[num] = str;
                    num++;
                    //strcat(tempprob,str);               
                    if(temp == brackets[1])
                    {   
                        Prob[num] = ")";
                        num++;
                        //strcat(tempprob,")");
                  
                    }
    
                    Prob[num] = " / ";
                    num++;
                    //strcat(tempprob," / ");
                    break;
                }
            }
        }
            
        /*******最后一个操作数***********/
        char strlast[10];
        sprintf(strlast,"%d",Operand[opnum-1]);
    
        Prob[num] = strlast;
        num++;
        //strcat(tempprob,strlast);
    
        if(opnum - 1 == brackets[1])
        {
            Prob[num] = ")";
                    
        }
    }
    •  第五步,问题显示,结果输入。
    •  第六步,结果的判断。四则运算结果计算,在数据结构中就曾经提到过,可以用二叉树、中序遍历、后续遍历等方法实现。在这次程序中,我采用的是用两个栈的方法。

    构建两个栈,一个保存操作数,一个保存算符,从左向右遍历表达式。

      1.遇到数字,压入操作数栈

      2.遇到算符则比较栈顶元素和算符的优先级

    • 1).栈顶元素比算符的优先级低,算符压栈
    • 2).栈顶元素与操作符的优先级相同,证明是配对的()或#,栈顶算符出栈
    • 3).栈顶元素比算符的优先级高,算符出栈1个,操作数出栈2个,计算完的结果压入操作数栈

    在优先级确定时,

    char Precedure(char a1, char a2)   //a1为前一个运算符,a2为后一个运算符
    {
     char r;
     switch(a2)
     {
     case '+':
     case '-':
      if(a1 == '(' || a1 == '#')
       r = '<';
      else
       r = '>';
      break;
     case '*':
     case '/':
      if(a1 == '*' || a1 == '/' || a1 == ')')
       r = '>';
      else
       r = '<';
      break;
     case '(':
      if(a1 == ')')
      {
       cout<<"括号匹配错误"<<endl;
       exit(-1);
      }
      else
       r = '<';
      break;
     case ')':
      if(a1 == '(')
       r = '=';
      else if(a1 == '#')
      {
       cout<<"error,没有左括号"<<endl;
      }
      else
       r = '>';
      break;
     case '#':
      switch(a1)
      {
      case'#':
       r='=';
       break;
      case'(':
       cout<<"error!没有右括号"<<endl;
       exit(-1);
      default:
       r='>';
      }//switch
      break; 
     }
     return r;
    }
    • 最后就是主函数的设计来实现定制数目、是否包含括号等功能,这一部分相对于前面几部分要容易的多,有一点需要注意,就是Problem类声明之前要有srand(time(0)),而非在类的声明里,如果是在里面的话,生成的题目的操作数的个数都是一样的会出现如下情况,失去了随机的意义。

    Problem类声明之前有srand(time(0)),类里没有,才真正实现操作数目的随机性,如下是修改后的情况。

    经网上资料及亲身实践知srand()反应时间大概50~60ms,而循环是很快就完成了,因此要将srand()放在循环外,才有用。

      好了,这个四则运算题就此结束,具体代码见  https://coding.net/u/zht01/p/Four_arithmetic-_operations/git/blob/master/kidtest_2.cpp

  • 相关阅读:
    第12组 Beta冲刺(2/5)
    第12组 Beta冲刺(1/5)
    第12组 Alpha事后诸葛亮
    第12组 Alpha冲刺(6/6)
    第12组 Alpha冲刺(5/6)
    期末大作业(第十七小组)
    补交:第2次&第5次实践作业
    第6次实践作业 (第17小组)
    第4次实践作业
    第3次实践作业
  • 原文地址:https://www.cnblogs.com/zht01/p/5270100.html
Copyright © 2011-2022 走看看