zoukankan      html  css  js  c++  java
  • 小学生*计算题

    MathExam—— 在原有的V2.0.0版本上加入三年级四则混合运算题

    • 211606335 吴沂章
    • 211606318 林锃寒

    一、预估与实际

    PSP2.1 Personal Software Process Stages 预估耗时(分钟) 实际耗时(分钟)
    Planning 计划
    • Estimate • 估计这个任务需要多少时间 5 3
    Development 开发
    • Analysis • 需求分析 (包括学习新技术) 90 720
    • Design Spec • 生成设计文档 20 20
    • Design Review • 设计复审 10 30
    • Coding Standard • 代码规范 (为目前的开发制定合适的规范) 30 10
    • Design • 具体设计 30 20
    • Coding • 具体编码 360 600
    • Code Review • 代码复审 20 300
    • Test • 测试(自我测试,修改代码,提交修改) 50 20
    Reporting 报告
    • Test Repor • 测试报告 30 20
    • Size Measurement • 计算工作量 30 20
    • Postmortem & Process Improvement Plan • 事后总结, 并提出过程改进计划 30 30
    合计 1793

    二、需求分析

    • 特点1

      • 运算符在2~4个
    • 特点2

      • 减法运算的结果不能有负数
    • 特点3

      • 除法运算除数不能为0,不能有余数
    • 特点4

      • 可以加括号

    经过分析,我认为,这个程序应当:

    • 一个式子中应要添加多个运算符

    • 计算符号判断,生成随机数

    • 通过调度场和逆波澜算法来实现运算


    三、设计

    1. 设计思路

    • 第一步实现四则运算题目的生成

    • 第二步实现字符串写入文本

    • 第三步实现从命令行接受参数并传入程序运行

    • 第四步实现 中缀表达式 ------转换------> 后缀表达式

    • 第五步实现对后缀表达式的计算方法

    • 最后修改若干Bug,规范代码名,完善代码,提升质量

    • ...

    • 代码类图
    • 逆波兰函数流程图:

    2. 实现方案

    • 准备工作:先在Github上创建仓库,克隆到本地,创建一个Pair文件夹

    • MyEclipse中创建一个类,包含主方法和各函数

    • 准备工作:先在Github上创建仓库,克隆到本地。

    • 技术关键点:

      • 如何令用户在输入 -n n -grade grade 和 -grade grade -n n 的时候都可以成功运行。

      • 如何在运算方法中实现"()"的优先运算

      • 如何在四则运算中添加括号。

      • 如何实现逆波澜算法

      • 如何记录错题。

      • ...

    四、编码

    • 本次代码未实现以下功能:
      - 除数为0的错误
      - 差值为负值的错误
      - 四则运算题目的数值的范围为[0,10),不能是2位数

    1. 调试日志

    • 日志一:
    • 没有考虑定义的运算符乘号小写字母"x"在入栈时被判定为符合要求的字符,导致判定出错
     private static boolean isOperator(String operator){
        if (operator.equals("+")||operator.equals("-")||operator.equals("×")||operator.equals("÷")||operator.equals("(")||operator.equals(")")) {
            return true;
        }
        return false;
    }
    
    
    • 解决方案:将所有乘法中的符号统一定义为输入法中的“×”
        无对应的解决方案代码
    
    • 日志二:
    • 生成三年级题目时调用i值导致抛异常为空值
    for (int j = 0; j < count; j++) {
        ....省略部分代码
        str_ArithmeticProblem[i] = "( " +n1 + " " + cs[c1] + " " + n2 +" ) " + " " + cs[c2] + " " + n3;
        ....省略部分代码
    }
    
    • 解决方案:将对应的循环值j放入str_ArithmeticProblem[j]中
    for (int j = 0; j < count; j++) {
        ....省略部分代码
        str_ArithmeticProblem[j] = "( " +n1 + " " + cs[c1] + " " + n2 +" ) " + " " + cs[c2] + " " + n3;
        ....省略部分代码
    }
    

    2. 关键代码

    • 调度场算法

    • 逆波兰函数

    //调度场算法——[中缀表达式转后缀表达式]
        private void toPostfixExpression(String str_mix){
            int len = str_mix.length();
            char c,nextChar;
            String sc;
            for (int i = 0 ; i <= len-1 ; i++) {
                c = str_mix.charAt(i); 
                sc = String.valueOf(c);
                if(isOperator(sc))  //判断是否是操作符
                {
                    if(operators.isEmpty()){    //判断为空栈,入栈
                        operators.push(sc);
                    } else {
                        if(priority(operators.peek()) < priority(sc) && !sc.equals(")")){   
                            //栈顶操作符优先级小于当前操作符优先级且操作符不为右括号,入栈
                            operators.push(sc);
                        } else if(priority(operators.peek()) >= priority(sc) && !sc.equals(")")){
                            while(!operators.empty() && !operators.peek().equals("(")   //栈不为空,当前栈顶操作符不为左括号
                                    && priority(operators.peek()) >= priority(sc)){     //操作符优先级小于等于当前栈顶操作符优先级
                                do {
                                    operator_Add = operators.pop();
                                    postfixExpression.append(operator_Add);
                                    operand.push(operator_Add);
                                } while (false);    }   // 栈顶操作符是左括号时停止压栈
                            operators.push(sc);     //否则直接入栈
                        } else if(sc.equals(")")){  //当前扫描到的操作符为右括号(不做入栈操作),依次压栈相匹配的左括号内容
                            do {
                                operator_Add = operators.pop();
                                postfixExpression.append(operator_Add);
                                operand.push(operator_Add);
                            } while (!operators.peek().equals("("));
                            operators.pop();    //弹出栈顶无用操作符左括号
                        }
                    }
                }else { //非操作符
                    if(!sc.equals(" ")){
                        postfixExpression.append(sc);
                        operand.push(sc);                   
                    }
                }
            }
            while(!operators.empty()){  //结束字符串扫描后操作符的栈不为空则则压栈
                operator_Add = operators.pop();
                postfixExpression.append(operator_Add);
                operand.push(operator_Add);
            }
        }
        
        
        //逆波兰函数
        private int reversePolish() {
            // TODO Auto-generated method stub
            char c;
            int len = postfixExpression.toString().length();
            for (int i = 0; i < len; i++) {
                c = postfixExpression.charAt(i);
                if(!isOperator(String.valueOf(c))){ //判断非操作符,入栈
                    postfixNumber.push(Integer.parseInt(String.valueOf(c)));
                } else{
                    int m = postfixNumber.pop();
                    int n = postfixNumber.pop();
                    String operator = String.valueOf(c);
                    postfixNumber.push(Calculation(n, m, operator));    
                }
            }
            return postfixNumber.pop();
        }
    

    3. 代码规范

    本次实验使用的代码规范:

    • 类名使用 UpperCamelCase 风格

    • 方法名、参数名、成员变量、局部变量都统一使用 lowerCamelCase 风格,遵循驼峰形式

    • 变量和常量的命名方式:

      • 非公有(private/protected/default)变量前面要加上小写m
      • 静态变量(static)前面加上小写s
      • 其它变量以小写字母开头
      • 静态常量(static final)全大写
    • 类型与中括号紧挨相连来定义数组

    • 大括号的使用约定。如大括号内为空,则简介地写成{}即可,不需要换行;如果是非空代码块则:

      • 左大括号前不换行
      • 左大括号后换行
      • 右大括号前换行
      • 右大括号后还有 else 等代码则不换行;表示终止的右大括号后必须换行
    • 左小括号和字符之间不出现空格;同样的,有小括号和字符之间也不出现空格

    4. 结对编程的过程

    • 我们采取的是Ping-Pong式的结对方式

    • 最初先是一起讨论这次项目的编码流程,研究用何种方式实现效果,并模拟程序运行得出这次的代码难点有哪些

    • 然后针对代码需要实现的功能进行分工,确立两个人的任务

    • 编程过程中互相交换意见,同步进程

    • 最后融合代码,并对代码进行复审

    五、测试

    序号 测试代码 预期输出结果 实际输出结果
    1 java MathExam -n 10 -grade 1 输出10道一年级算术题 和预期结果相符
    2 java MathExam -n 10 -grade 2 输出10道二年级算术题 和预期结果相符
    3 java MathExam -n 10 -grade 3 输出10道三年级算术题 和预期结果相符
    4 java MathExam -grade 3 -n 10 输出10道三年级算术题 和预期结果相符
    5 java MathExam -grade 2 -n 10 输出10道二年级算术题 和预期结果相符
    6 java MathExam -grade 1 -n 10 输出10道一年级算术题 和预期结果相符
    7 java MathExam -g 3 -n 10 不符合参数类型输入规范,结束程序 和预期结果相符
    8 java MathExam -grade 3 -c 10 不符合参数类型输入规范,结束程序 和预期结果相符
    9 java MathExam 10 -grade 1 不符合参数类型输入规范,结束程序 和预期结果相符
    10 java MathExam -g 10 -c 1 不符合参数类型输入规范,结束程序 和预期结果相符

    六、总结

    • 随着题目要求难度越来越高,所写的代码也越来越长,一定要多写注释提醒自己
    • 先对本次项目进行需求分析,避免重复修改代码时产生不必要的bug
    • 结对编程的过程中,跟自己的搭档要商量好各自的任务,若是各写各的,一人一个版本,会给后续的代码融合增加很大的难度
    • 结对编程中一个人写完了自己的任务,也不要自顾自的放松,这是两个人的项目,应该帮助自己的搭档
    • 结对编程中与队友一起探讨代码中无数bug也是很快乐的
    • 这次代码难度还是很高的,还好我们彼此之间相互鼓励,相互帮助,总算是能给客户看了

  • 相关阅读:
    Qt新建线程的方法(有QRunnable,QThreadPool,moveToThread和QtConcurrent的例子)
    QThread 与 QObject的关系(QObject可以用于多线程,可以发送信号调用存在于其他线程的slot函数,但GUI类不可重入)
    Qt线程QThread简析(8个线程等级,在UI线程里可调用thread->wait()等待线程结束,exit()可直接退出线程,setStackSize设置线程堆栈,首次见到Qt::HANDLE,QThreadData和QThreadPrivate)
    QSettings保存程序设置
    QList 和std::list的比较
    转义字符()对JavaScript中JSON.parse的影响
    自定义类似QMutexLocker的CMutexLocker
    部件之间图标拖拽(使用很直观,效果很漂亮)
    QtSoap调用Web Service(QtSoap是非官方应用)
    QTableWidget 导出到csv表格
  • 原文地址:https://www.cnblogs.com/linzenghan/p/9672383.html
Copyright © 2011-2022 走看看