结队编程:小学四则运算

这个作业属于哪个课程广工2023软件工程
这个作业要求在哪里结队编程:小学四则运算
这个作业的目标实现一个四则运算题目的程序
其他参考文献csdn,百度

结对信息:

姓名学号
龙依婷3221005155
方喜加3221005152

仓库地址

一、PSP表格

PSP2.1Personal Software Process Stages预估耗时(分钟)实际耗时(分钟)
Planning计划2030
· Estimate· 估计这个任务需要多少时间2030
Development开发665728
· Analysis· 需求分析 (包括学习新技术)80107
· Design Spec· 生成设计文档2025
· Design Review· 设计复审 (和同事审核设计文档)1018
· Coding Standard· 代码规范 (为目前的开发制定合适的规范)156
· Design· 具体设计4057
· Coding· 具体编码360402
· Code Review· 代码复审6050
· Test· 测试(自我测试,修改代码,提交修改)8063
Reporting报告70105
· Test Report· 测试报告4072
· Size Measurement· 计算工作量2016
· Postmortem & Process Improvement Plan· 事后总结, 并提出过程改进计划1017
合计755863

二、效能分析

在这里插入图片描述

在这里插入图片描述
由图可知,byte[]所占资源最大

三、设计实现过程

项目结构图

项目结构

主函数流程图

在这里插入图片描述

关键函数流程图
生成题目的函数

生成题目

计算题目的函数

在这里插入图片描述

四、代码说明

生成题目
/**
     * 生成n道题目,并且操作数在range范围内
     * @param n     题目个数
     * @param range 数值范围
     * @return 返回
     */
    public static Map<String, String> getProblem(int n, int range) {

        //运算式和结果的集合
        Map<String, String> problem_result = new HashMap<>();
        //结果集合,用于判断是否重复
        Set<String> results = new HashSet<>();
        //获取n道题目
        for (int i = 0; i < n; i++) {
            //随机获取1~3个运算符数量
            int operator = (int) (Math.random() * 3) + 1;
            //随机获取operator个运算符
            Character[] operators = getOperator(operator);
            //随机获取operator+1个操作数,且范围在range内
            String[] operand = getOperand(operator + 1, range);
            //获取运算式表达式
            String[] expression = getExpression(operators, operand);
            //判断是否为负数
            if ((expression == null || expression[1].contains("-")) || results.contains(expression[1])) i--;
            else {
                results.add(expression[1]);
                //expression[0]:运算式;expression[1]:结果
                problem_result.put(expression[0], expression[1]);
            }
        }
        return problem_result;
    }
检查答案正确
 /**
     * 验证答案的正确率,并记录到Grade.txt文件中
     * @param exerciseUrl 练习题文件路径
     * @param answerUrl 答案文件路径
     */
    public static void checkAccuracy(String exerciseUrl, String answerUrl) {
        File exerciseFile = new File(CheckUtil.fullPath(exerciseUrl));
        File answerFile = new File(CheckUtil.fullPath(answerUrl));
        File gradeFile = new File(Constants.FILE_ADDRESS, "Grade.txt");
        if (exerciseFile.isFile() && answerFile.isFile()) {//当两个文件是标准文件时
            BufferedReader exerciseReader = null;
            BufferedReader answerReader = null;
            OutputStream gradeFileOutputStream = null;

            List<Integer> Correct = new ArrayList<>();
            List<Integer> Wrong = new ArrayList<>();
            try {
                exerciseReader = new BufferedReader(new InputStreamReader(Files.newInputStream(exerciseFile.toPath())));
                answerReader = new BufferedReader(new InputStreamReader(Files.newInputStream(answerFile.toPath())));
                String exercise;
                String answer;
                String[] exerciseStr;
                String[] answerStr;
                int line = 0;//记录行数
                while (null != (exercise = exerciseReader.readLine()) && null != (answer = answerReader.readLine())) {
                    exerciseStr = exercise.split("、");
                    answerStr = answer.split("、");
                    //获取运算式的正确答案
                    String correctAnswer = AriUtil.getExpressValue(exerciseStr[1]);
                    if (correctAnswer.equals(answerStr[1])) {
                        line++;
                        Correct.add(line);
                    } else {
                        line++;
                        Wrong.add(line);
                    }
                }
                String result = "Correct:" + Correct.size() + Correct + "\r\n" + "Wrong:" + Wrong.size() + Wrong;
                //保存成绩文件
                gradeFileOutputStream = Files.newOutputStream(gradeFile.toPath());
                gradeFileOutputStream.write(result.getBytes());
                System.out.println("统计结果在Grade.txt文件中");
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if (exerciseReader != null) {
                    try {
                        exerciseReader.close();
                    } catch (IOException ignored) {
                    }
                }
                if (answerReader != null) {
                    try {
                        answerReader.close();
                    } catch (IOException ignored) {
                    }
                }
                if (gradeFileOutputStream != null) {
                    try {
                        gradeFileOutputStream.close();
                    } catch (IOException ignored) {
                    }
                }
            }

        } else {
            System.out.println("该文件不存在!!!");
        }
    }
计算题目正确答案
/**
     * 运用了调度场算法,计算一个题目的初步计算结果
     *
     * @param question 题目
     * @return 初步计算结果
     */
    public static String getExpressValue(String question) {
        //栈operand放置操作数,包含整数和分数
        Stack<Fraction> operand = new Stack<>();
        //栈operator放置运算符,包含 +、-、*、÷和括号
        Stack<Character> operator = new Stack<>();

        char[] problem = question.toCharArray();   //将题目字符串转换为一个新的字符数组。
        char ch;

        for (int i = 0; i < problem.length; i++) {
            //获取当前的字符
            ch = problem[i];
            //当字符为左括号时,入栈
            if (ch == '(') {
                operator.push(ch);
            } else if (ch == ')') {
                //运算符栈顶元素不是‘(’
                while (operator.peek() != '(') {
                    //拿取操作数栈中的两个操作数
                    Fraction fraction1 = operand.pop();
                    Fraction fraction2 = operand.pop();
                    //计算结果
                    Fraction result = calculate(operator.pop(), fraction1.getNumerator(), fraction1.getDenominator(),
                            fraction2.getNumerator(), fraction2.getDenominator());

                    if (result.getNumerator() < 0) return "#";
                    //将结果压栈
                    operand.push(result);
                }
                //将'('出栈
                operator.pop();
            } else if (ch == '+' || ch == '-' || ch == '*' || ch == '÷') {
                //运算符栈不为空,当前运算符小于栈顶运算符优先级
                while (!operator.empty() && !priority(ch, operator.peek())) {
                    //取操作栈中的两个分数
                    Fraction fraction1 = operand.pop();
                    Fraction fraction2 = operand.pop();
                    //得到计算后的值
                    Fraction result = calculate(operator.pop(), fraction1.getNumerator(), fraction1.getDenominator(),
                            fraction2.getNumerator(), fraction2.getDenominator());
                    if (result.getNumerator() < 0) {
                        return "#";
                    }
                    //将结果压栈
                    operand.push(result);
                }
                //将运算符入栈
                operator.push(ch);
            } else {//当字符是操作数的时候
                if (ch >= '0' && ch <= '9') {
                    StringBuilder buf = new StringBuilder();
                    //取出一个完整的数值 比如 2/3、5、7/39
                    while (i < problem.length && (problem[i] == '/' || ((problem[i] >= '0') && problem[i] <= '9'))) {
                        buf.append(problem[i]);
                        i++;
                    }
                    i--;
                    //buf里面是一个操作数
                    String val = buf.toString();
                    //标记‘/’的位置
                    int flag = val.length();
                    for (int k = 0; k < val.length(); k++) {
                        //当得到的数在/标记/的位置,然后生成分数对象
                        if (val.charAt(k) == '/') {
                            flag = k;
                        }
                    }
                    //分子
                    StringBuilder numeratorBuf = new StringBuilder();
                    //分母
                    StringBuilder denominatorBuf = new StringBuilder();
                    for (int j = 0; j < flag; j++) {
                        numeratorBuf.append(val.charAt(j));
                    }
                    //判断是否为分数,如果是分数,则flag不为val.length
                    if (flag != val.length()) {
                        for (int q = flag + 1; q < val.length(); q++) {
                            denominatorBuf.append(val.charAt(q));
                        }
                    } else {//不是分数 分母为1
                        denominatorBuf.append('1');
                    }
                    //入栈
                    operand.push(new Fraction(Integer.parseInt(numeratorBuf.toString()), Integer.parseInt(denominatorBuf.toString())));
                }
            }
        }

        while (!operator.empty()) {
            Fraction fraction1 = operand.pop();
            Fraction fraction2 = operand.pop();

            //得到运算后的值
            Fraction result = calculate(operator.pop(), fraction1.getNumerator(), fraction1.getDenominator(),
                    fraction2.getNumerator(), fraction2.getDenominator());
            if (result.getNumerator() < 0) {
                return "#";
            }
            //结果压栈
            operand.push(result);
        }

        Fraction result = operand.pop();
        //将分数约分
        return reduction(result);

    }

五、测试运行

测试代码覆盖率

测试用例没有用到main函数,所以Main覆盖率为0
测试覆盖率

  1. 生成1万道题和正确答案
    在这里插入图片描述
    在这里插入图片描述
  2. 1万道题的答案比对
    在这里插入图片描述
    生成1万道题
  3. 正常生成2道题
    生成两道题并成功运行
  4. -n 参数错误 Main.exe -n -2 -r 200
    在这里插入图片描述
  5. -r 参数错误 Main.exe -n 2 -r -200
    在这里插入图片描述
  6. 题目文件名错误 Main.exe -e Exe.txt -a Answers.txt
    在这里插入图片描述
  7. 答案文件名错误 Main.exe -e Exercises.txt -a Answ.txt
    在这里插入图片描述
  8. 直接-e Exercises.txt -a Answers.txt
    在这里插入图片描述
  9. 使用doc文件类型 Main.exe -e Exercises.txt -a Answer.doc
    在这里插入图片描述

六、项目小结

在这次结对编程的体验中,可以充分发挥两个人的优点,共同进步,实现1+1 > 2的效果,我负责测试及博客的编写,队友负责写算法及性能分析。我们采用一个人编程,一个人监督并帮忙的模式;达到一定时间角色互换,思维互换,这样既不会思维僵硬,还能学到对方身上的优点,还可以解决不专注问题。如果一个人编程感觉枯燥,进行不下去了,另一个就积极与她沟通,并帮忙编程。一开始,效果并不理想,我们两个的代码思路有分歧,但是在后面的开发过程中,我们不断沟通,借鉴前人的经验,出现了问题,一起想办法解决,包容不同的思想,从中获取经验,开发效率得到很大提高。在这个过程中,我们收获的不仅是编程能力的提高,更是团队协作,沟通能力和表达能力的提高。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 适合毕业设计、课程设计作业。这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。 所有源码均经过严格测试,可以直接运行,可以放心下载使用。有任何使用问题欢迎随时与博主沟通,第一时间进行解答!
提供的源码资源涵盖了小程序应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 适合毕业设计、课程设计作业。这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。 所有源码均经过严格测试,可以直接运行,可以放心下载使用。有任何使用问题欢迎随时与博主沟通,第一时间进行解答!
提供的源码资源涵盖了Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 适合毕业设计、课程设计作业。这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。 所有源码均经过严格测试,可以直接运行,可以放心下载使用。有任何使用问题欢迎随时与博主沟通,第一时间进行解答!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值