小学生究极进化---四则混合运算

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
  • 结对编程的过程中,必须要做到分工明确,对代码要达成统一的意见,而不是各写各的
  • 结对编程中两人的节奏需保持一致,否则一个人写完了自己的任务,开始玩起了游戏,另一个便会浮躁不安
  • 每次版本更新后都尽量提交到GitHub进行托管,比如说这次遇到了对代码更改后无法恢复原点,就可以借助GitHub的托管进行恢复

posted @ 2018-09-19 02:24  中国制造  阅读(237)  评论(0编辑  收藏  举报