• 软件工程第3次作业—四则运算(结对作业)


    作业要求的博客链接:https://edu.cnblogs.com/campus/nenu/2016CS/homework/2266

    git仓库地址:https://git.coding.net/pipifan/f4.git

     本次作业是结对作业,我的结对伙伴是樊友朋同学,他的博客地址是:http://www.cnblogs.com/pipifan/p/9918250.html

     项目概要:

      本次项目实现的是一个用于四则运算的控制台程序,目前已实现的功能如下:

      1)支持整数和不含括号的四则运算且表达式可以重复。

      2)支持小数和含小括号的四则运算且表达式可以重复。

      3)表达式不重复且输出结果显示在控制台,然后将控制台显示的结果输出到指定位置的txt文件中。

     

    项目详情:

    一、本次作业采用c/c++进行编程。首先分析项目要求概括功能:

      1)按照控制台输入的N ,生成N道由随机生成的整数合法运算符组成的四则运算,并判断用户输入答案的对错。(输入 f4 -n N)

      2)按照控制台输入的N ,生成N道由随机生成的整数小数合法运算符括号组成的四则运算,并判断用户输入答案的对错。(输入 f4 -c N )

      3)按照控制台输入的N 、文件路径M,生成N道由随机生成的整数小数合法运算符括号组成的不重复的四则运算,给出答案打印在控制台输出到文件M中。(输入 f4 -c  N  -f M)

      4)如果输入的N不合法会输出相应的警告。

    二、根据分析规划函数模块:

       1)字符串转化为数字。

       2)判断运算符号的优先级。

       3)处理四则运算表达式,计算表达式的值。

       4)处理控制台输入输出,产生随机数,随机运算符号和随机括号。

       5)主函数,负责调用各个模块,控制流程。

    三、部分模块代码实现过程:

      1)处理四则运算表达式。

    首先分配两个栈sp,sv,分别存储运算符和运算数字,从左到右读取中缀表达式,遇到操作数就入栈sv,遇到左括号或者当前运算符比sp栈顶优先级高的符号就入栈sp,遇到比sp栈顶优先级低的符号就出栈两个操作数和栈顶操作符,结果再入栈sv,遇到右括号同时栈顶是左括号就出栈左括号。最后sv栈顶就是该表达式的结果。

    具体代码如下:

    double solve(string s )
    {
        stack<double> sv;
        stack<char> sp;
        char c;
        int k = 0, flag = 1;
        double x, y;
        sp.push('');
        c = s[k];
        while (flag)
        {
            if (c >= '0'&&c <= '9' || c == '.') {
                sv.push(toNum(s, k));
            }
            else if (c == ''&& sp.top() == '') {
                flag = 0;
            }
            else if (c == '(' || (priority(c) > priority(sp.top()))) {
                sp.push(c);
                k++;
            }
            else if (c == ')'&& sp.top() == '(') {
                sp.pop();
                k++;
            }
            
            else if (priority(c) <= priority(sp.top())) {
                x = sv.top();
                sv.pop();
                if(sv.empty()) y = 0;
                else {
                    y = sv.top();
                    sv.pop();
                }
                c = sp.top();
                if( c == '/' && fabs( x ) <= eps ){
                    int num = rand() % 3;
                    c = mp[num];
                }
                sp.pop();
                switch (c) {
                    case '+':y = x + y; break;
                    case '-':y = y - x; break;
                    case '*':y = x*y; break;
                    case '/':y = y / x; break;
                }
                sv.push(y);
            }
            c = s[k];
        }
        return sv.top();
    }

       2)随机生成整数数字和运算符。

    实现功能一用rand随机生成数字和运算符(提前存到数组中)。

    这里在实现过程中有两点我们进行了思考:其一是单纯用rand()会使每次的随机数一样,这样就不符合随机这个概念,所以我们加上 srand( (int)time(0) ),用时间做随机数的种子,这样可以保证每次的随机数不同。其二是考虑到除数不能为0,所以我们判断如果“/”后面的随机数是0就再造数据直至不为0,保证了表达式的正确性。

    s = "";
            if( flag == 1 ){
                for(int i = 0 ; i < 7 ; i++ ){
                    if( (i % 2) == 0 ){
                        int num = rand() % 10;
                        int len = s.size();
                        while( len > 0 && num == 0 && s[len - 1] == '/' )
                            num = rand() % 10;
                        stringstream ss;
                        ss << num;
                        string tmp;
                        ss >> tmp;
                        s += tmp;
                    }
                    else{
                        int num = rand() % 4;
                        s += mp[num];
                    }
                }
            }

        3)随机生成带括号的整数和小数的数据。

    生成小数时用两个随机数相除。

    这里的难点是随机加括号,我们采取的办法是先随机加左右括号,最后检查是否匹配,缺少匹配的括号就在表达式首尾加上相应的括号。

    for(int i = 0 ; i < 7 ; i++ ){
                    string tmp;
                    if( (i % 2) == 0 ){
                        int num = rand() % 10;
                        if( (num % 3) == 0 && num > 0 ){
                            int num1 = rand() % 100;
                            double tmp_num = num1*1.0 / 10;
                            stringstream ss;
                            ss << tmp_num;
                            ss >> tmp;
                            x[xx++] = tmp_num;
                        }
                        else{
                            int len = s.size();
                            while( len > 0 && num == 0 && s[len - 1] == '/' )
                                num = rand() % 10;
                            stringstream ss;
                            ss << num;
                            ss >> tmp;
                            x[xx++] = num*1.0;
                        }
                        if( num < 3 && i < 6 && i > 0 ){
                            s += "(";
                            cnt1++;
                        }
                        s += tmp;
                        if( num > 6  && i > 0 && i < 6){
                            if( cnt1 > 0 )
                                cnt1--;
                            else
                                cnt2++;
                            s += ")";
                        }
                    }
                    else{
                        int num = rand() % 4;
                        s += mp[num];
                    }
                }

    四、测试阶段:

         1)功能1

     

         2)功能2

        3)功能3

    五、项目进行过程

    1.给出结对编程的体会  

    结对编程的好处是可以集思广益,尤其针对本次作业的一些小的细节可以做到查漏补缺。

    比如输入参数错误时的文字提示,功能一和功能二的提示是不同的;比如除数不能为0;比如保留小数的位数时要考虑是否为有限小数,无限小数要保留三位;比如功能三输出时要对齐......等等的一些问题。在解决功能二中如何随机加括号,并且如何匹配正确时,两个人也进行了各自的思考然后加以讨论得出解决方案。在查找相应的参考资料时也更便捷。

    由于结对编程需要共用一个设备,所以编程以平时写代码能力比较强的樊友朋同学为主,相当于Driver,我负责收集整理资料、提供思路,发现、修改细节问题和测试数据,相当于Navigator。我对结对编程的体会应该是分清主次,各司其职,需要默契,在讨论中解决问题和完善项目。在《构建之法》中也提到过结对编程的好处,“结对能带来更多的信心,高质量的产出可以带来更高的满足感。”,通过这次结对作业,确实感受的优秀的队友带来的不同的合作感,更加有利于问题的解决。

    2. 至少3项在编码、争论等活动中花费时间较长,给你较大收获的事件。

      1). 用栈处理四则运算表达式。具体思路可以参考3.1

      2). 随机生成小数和括号。主要的难点是随机加括号,并且要保证括号的正确性。具体思路参考3.3

      3). 功能二和三要求表达式不重复。初看作业要求中的不重复概念是要运用交换律、结合律等数学定理来检测题的不重复性,但是这样比较麻烦。所以经过讨论后,我的伙伴提出为了保证题的不重复,可以检查每个题中的数字是否相同。因为题目本身是由随机数、随机括号、随机运算符组成的,它重复的概率很低,所以我们把表达式的数字排序,包装放在set里面,检查数字重复时就重新生成表达式,这样不会影响随机性,也不会有重复的表达式,最重要的是降低算法复杂度(相对检查交换律的那种算法)

      4). 花费时间长的地方还有5.1提到的细节问题,为了尽力满足作业要求,我们用了大概两至三个小时去修改细节。

    六、给出照片1张,包括结对的2位同学、工作地点、计算机,可选项包括其他能表达结对编程工作经历的物品或场景。

  • 相关阅读:
    JavaScript-循环
    JavaScript-条件判断
    JavaScript-对象
    Vue快速入门
    Typora中的MarkDown语法
    (已解决)ERROR: In file './docker-compose.yml', service 'networks' must be a mapping not an array
    mac常用快捷键
    Python数据分析
    Python列表和元组
    Selenium工具爬取商品
  • 原文地址:https://www.cnblogs.com/kongwy/p/9919850.html
Copyright © 2020-2023  润新知