首页 > 其他分享 >结对项目

结对项目

时间:2024-09-26 16:50:23浏览次数:6  
标签:分数 结对 return String 项目 int 带分数 运算符

这个作业属于哪个课程 https://edu.cnblogs.com/campus/gdgy/CSGrade22-34
这个作业要求在哪里 https://edu.cnblogs.com/campus/gdgy/CSGrade22-34/homework/13230
这个作业的目标 <结对合作完成项目,实现一个自动生成小学四则运算题目的命令行程序>
成员1 唐立伟 3122005404
成员2 黄妍仪 3222004767

Github链接

https://github.com/tangliweiwww/Arithmetic

PSP2.1表格

PSP2.1 Personal Software Process Stages 预估耗时(分钟) 实际耗时(分钟)
Planning 计划 50 60
· Estimate · 估计这个任务需要多少时间 700 750
Development 开发 450 530
· Analysis · 需求分析 (包括学习新技术) 50 55
· Design Spec · 生成设计文档 25 25
· Design Review · 设计复审 (和同事审核设计文档) 25 30
· Coding Standard · 代码规范 (为目前的开发制定合适的规范) 20 35
· Design · 具体设计 50 55
· Coding · 具体编码 200 240
· Code Review · 代码复审 40 40
· Test · 测试(自我测试,修改代码,提交修改) 40 50
Reporting 报告 100 125
· Test Report · 测试报告 40 45
· Size Measurement · 计算工作量 40 55
· Postmortem & Process Improvement Plan · 事后总结, 并提出过程改进计划 20 25
合计 600 715

程序设计

类名 方法名 用途
FractionCalculator evaluateFractionExpression 计算
parseFraction 解析分数为BigFraction
isOperator 判断符号
precedence 设定优先级
applyOperator 进行数学运算
FractionChange convertExpressionToMixedFractions 将算式中的分式转换为带分数
convertMixedFractionsToImproperFractions 将带分数转换为普通分数
MathProblemGenerator generateRandomProblem 生成一个随机题目
generateOperand 生成操作数
evaluateOperand 计算操作数的值
isValidExpression 检查计算结果是否符合要求
WriteToFile_ProblemAndAnswers Write 生成答案和题目并写入文件
Judge JudgeFile 生成判题结果写入文件

执行流程

代码说明

MathProblemGenerator

用于生成题目,实现了一个数学题目生成器,能够生成带有分数的数学表达式。
生成随机题目:通过 generateUniqueProblems 方法生成指定数量的唯一数学题目,确保每个题目都是合法的。
表达式构造:使用 generateRandomProblem 方法随机生成操作数和运算符,支持加、减、乘、除等基本运算,并随机决定是否使用括号。
合法性检查:isValidExpression 方法使用第三方库解析生成的表达式,并验证其结果是否符合要求(如非负)。
分数和整数生成:generateOperand 方法随机生成整数或分数,确保题目的多样性。
结果评估:evaluateOperand 方法计算操作数的值,支持分数的计算。

public class MathProblemGenerator {

    private static final Random RANDOM = new Random(); // 随机数生成器
    // 生成唯一题目集合
    public static Set<String> generateUniqueProblems(int numberOfProblems, int range) {
        Set<String> problems = new LinkedHashSet<>(); // 使用LinkedHashSet保持插入顺序
        while (problems.size() < numberOfProblems) {
            String problem = generateRandomProblem(range); // 生成随机题目
            if (isValidExpression(problem)) { // 检查题目是否合法
                problems.add(FractionChange.convertExpressionToMixedFractions(problem)); // 转换为混合分数并添加到集合
            }
        }
        return problems; // 返回生成的题目集合
    }

    // 生成一个随机题目
    private static String generateRandomProblem(int range) {
        String[] operators = {"+", "-", "*", "/"}; // 可用运算符
        StringBuilder problem = new StringBuilder(); // 存储生成的题目
        Stack<Boolean> parenthesesStack = new Stack<>(); // 用于管理括号的栈

        // 生成两个操作数和一个运算符
        String operand1 = generateOperand(range); // 生成第一个操作数
        String operand2 = generateOperand(range); // 生成第二个操作数
        String operator = operators[RANDOM.nextInt(operators.length)]; // 随机选择一个运算符

        // 确保减法时前面的数大于等于后面的数
        if ("-".equals(operator)) {
            while (evaluateOperand(operand1) < evaluateOperand(operand2)) {
                operand1 = generateOperand(range); // 重新生成第一个操作数
                operand2 = generateOperand(range); // 重新生成第二个操作数
            }
        }

        // 随机决定是否生成括号
        if (RANDOM.nextBoolean()) {
            problem.append("(");
            parenthesesStack.push(true);  // 打开括号
        }

        // 组装题目
        problem.append(operand1)
                .append(" ")
                .append(operator)
                .append(" ")
                .append(operand2);

        // 随机决定是否生成第二部分的表达式
        if (RANDOM.nextBoolean()) {
            operator = operators[RANDOM.nextInt(operators.length)];
            String operand3 = generateOperand(range); // 生成第三个操作数
            String operand4 = generateOperand(range); // 生成第四个操作数

            // 确保减法时前面的数大于等于后面的数
            if ("-".equals(operator)) {
                while (evaluateOperand(operand3) < evaluateOperand(operand4)) {
                    operand3 = generateOperand(range);
                    operand4 = generateOperand(range);
                }
            }

            problem.append(" ")
                    .append(operator)
                    .append(" ");

            // 随机决定是否给第二部分加括号
            if (RANDOM.nextBoolean()) {
                problem.append("(");
                parenthesesStack.push(true);  // 打开括号
            }

            problem.append(operand3)
                    .append(" ")
                    .append(operators[RANDOM.nextInt(operators.length)]) // 随机选择运算符
                    .append(" ")
                    .append(operand4);

            // 关闭括号
            while (!parenthesesStack.isEmpty()) {
                problem.append(")");
                parenthesesStack.pop(); // 关闭括号
            }
        }

        // 如果还有未关闭的括号,最后关闭它
        while (!parenthesesStack.isEmpty()) {
            problem.append(")");
            parenthesesStack.pop(); // 关闭剩余的括号
        }

        return problem.toString(); // 返回生成的题目字符串
    }

    // 生成操作数
    private static String generateOperand(int range) {
        if (RANDOM.nextBoolean()) {
            // 生成整数
            return String.valueOf(RANDOM.nextInt(range) + 1);
        } else {
            // 生成分数
            int numerator = RANDOM.nextInt(range) + 1; // 随机生成分子
            int denominator = RANDOM.nextInt(range) + 1; // 随机生成分母
            return numerator + "/" + denominator; // 返回分数形式
        }
    }

    // 计算操作数的值
    private static double evaluateOperand(String operand) {
        if (operand.contains("/")) {
            String[] parts = operand.split("/"); // 分割分数
            return Double.parseDouble(parts[0]) / Double.parseDouble(parts[1]); // 计算并返回小数值
        } else {
            return Double.parseDouble(operand); // 返回整数值
        }
    }

    // 检查计算结果是否符合要求
    private static boolean isValidExpression(String expression) {
        // 创建表达式解析器
        Expression e = new ExpressionBuilder(expression).build();
        // 计算并返回结果
        double result = e.evaluate();
        // 如果结果小于0,则不合法
        if (result < 0) {
            return false;
        }
        return true; // 合法表达式
    }
}

FractionChange

这段代码主要实现了分数和带分数之间的转换功能。主要功能包括:
分数转换为带分数:使用正则表达式查找算式中的普通分数,并将其转换为带分数形式。
带分数转换为普通分数:提供功能将带分数(如 2'1/3)转换为不合适分数(如 7/3)。
分数解析与化简:解析输入的分数字符串,将其分解为分子和分母,并通过计算最大公约数(GCD)对分数进行化简。

public class FractionChange {
    // 将算式中的分式转换为带分数
    public static String convertExpressionToMixedFractions(String expression) {
        // 正则表达式匹配分数
        Pattern fractionPattern = Pattern.compile("(\\d+/\\d+)");
        Matcher matcher = fractionPattern.matcher(expression);
        StringBuffer result = new StringBuffer();

        // 查找并转换分数
        while (matcher.find()) {
            String fraction = matcher.group(1);
            int[] parsedFraction = parseFraction(fraction); // 解析分数
            String mixedFraction = convertToMixedFraction(parsedFraction[0], parsedFraction[1]); // 转换为带分数
            matcher.appendReplacement(result, mixedFraction); // 替换为带分数
        }
        matcher.appendTail(result); // 添加剩余部分

        return result.toString(); // 返回转换后的表达式
    }

    // 将字符串形式的分数解析为整数数组,返回[分子, 分母]
    public static int[] parseFraction(String fraction) {
        String[] parts = fraction.split("/"); // 分割字符串
        int numerator = Integer.parseInt(parts[0]); // 分子
        int denominator = Integer.parseInt(parts[1]); // 分母
        return new int[] {numerator, denominator};
    }

    // 求最大公约数(GCD)
    public static int gcd(int a, int b) {
        if (b == 0) {
            return a; // 递归终止条件
        }
        return gcd(b, a % b); // 计算GCD
    }

    // 将分数转换为带分数形式并化简
    public static String convertToMixedFraction(int numerator, int denominator) {
        // 化简分数部分
        int gcd = gcd(numerator, denominator); // 计算GCD
        numerator /= gcd; // 简化分子
        denominator /= gcd; // 简化分母

        // 如果分子小于分母,直接返回简化后的普通分数
        if (numerator < denominator) {
            return numerator + "/" + denominator;
        }

        // 计算整数部分和余数
        int wholeNumber = numerator / denominator;
        int remainder = numerator % denominator;

        // 如果没有余数,返回整数
        if (remainder == 0) {
            return Integer.toString(wholeNumber);
        }

        // 否则返回带分数形式(化简后的结果)
        return wholeNumber + "'" + remainder + "/" + denominator;
    }

    // 将带分数转换为普通分数
    public static String convertMixedFractionsToImproperFractions(String expression) {
        // 正则表达式匹配带分数
        Pattern mixedFractionPattern = Pattern.compile("(\\d+)'(\\d+)/(\\d+)");
        Matcher matcher = mixedFractionPattern.matcher(expression);
        StringBuffer result = new StringBuffer();

        // 查找并转换带分数
        while (matcher.find()) {
            String mixedFraction = matcher.group();
            String improperFraction = convertMixedFractionToImproperFraction(mixedFraction); // 转换为普通分数
            System.out.println("Converting: " + mixedFraction + " to " + improperFraction); // 调试输出
            matcher.appendReplacement(result, improperFraction); // 替换为普通分数
        }
        matcher.appendTail(result); // 添加剩余部分

        return result.toString(); // 返回转换后的表达式
    }

    // 将带分数形式转换为普通分数
    public static String convertMixedFractionToImproperFraction(String mixedFraction) {
        // 正则表达式匹配带分数
        Pattern mixedFractionPattern = Pattern.compile("(\\d+)'(\\d+)/(\\d+)");
        Matcher matcher = mixedFractionPattern.matcher(mixedFraction);

        if (matcher.matches()) {
            int wholeNumber = Integer.parseInt(matcher.group(1)); // 整数部分
            int numerator = Integer.parseInt(matcher.group(2)); // 分子
            int denominator = Integer.parseInt(matcher.group(3)); // 分母

            // 将带分数转换为普通分数
            int improperNumerator = wholeNumber * denominator + numerator; // 计算不合适分子
            return improperNumerator + "/" + denominator; // 返回普通分数形式
        } else {
            // 处理未匹配带分数形式的情况(可以是普通分数形式)
            return mixedFraction; // 返回原分数形式
        }
    }
}

FractionCalculator

这段代码实现了一个分数计算器,能够解析和计算包含分数的数学表达式。它的主要功能包括:
表达式解析:使用栈数据结构来管理数值和运算符,以支持复杂表达式的评估。
分数处理:提供了将字符串格式的分数转换为 BigFraction 对象的方法,支持加、减、乘、除等基本运算。
运算符优先级:通过优先级规则确保正确的运算顺序。
错误处理:处理了除以零的情况和无效运算符,确保计算过程中的安全性和稳定性。

public class FractionCalculator {

    // 评估包含分数的数学表达式
    public static BigFraction evaluateFractionExpression(String expression) throws IllegalArgumentException {
        Stack<BigFraction> values = new Stack<>(); // 存储数值的栈
        Stack<Character> operators = new Stack<>(); // 存储运算符的栈

        // 使用字符串分割器来解析表达式
        StringTokenizer tokenizer = new StringTokenizer(expression, "()+-*/", true);

        while (tokenizer.hasMoreTokens()) {
            String token = tokenizer.nextToken().trim(); // 获取下一个标记并去掉空格

            if (token.isEmpty()) continue; // 忽略空标记

            if (token.equals("(")) {
                operators.push('('); // 如果是左括号,压入运算符栈
            } else if (token.equals(")")) {
                // 当遇到右括号时,处理直到遇到左括号
                while (operators.peek() != '(') {
                    values.push(applyOperator(operators.pop(), values.pop(), values.pop()));
                }
                operators.pop(); // 弹出左括号
            } else if (isOperator(token.charAt(0))) {
                // 处理运算符的优先级
                while (!operators.isEmpty() && precedence(operators.peek()) >= precedence(token.charAt(0))) {
                    values.push(applyOperator(operators.pop(), values.pop(), values.pop()));
                }
                operators.push(token.charAt(0)); // 压入当前运算符
            } else {
                values.push(parseFraction(token)); // 将标记解析为分数并压入值栈
            }
        }

        // 处理剩余的运算符
        while (!operators.isEmpty()) {
            values.push(applyOperator(operators.pop(), values.pop(), values.pop()));
        }

        return values.pop(); // 返回最终结果
    }

    // 将字符串标记解析为分数
    private static BigFraction parseFraction(String token) {
        if (token.contains("/")) {
            String[] parts = token.split("/"); // 分割分子和分母
            return new BigFraction(Integer.parseInt(parts[0]), Integer.parseInt(parts[1]));
        } else {
            return new BigFraction(Integer.parseInt(token), 1); // 整数作为分数处理
        }
    }

    // 检查字符是否为运算符
    private static boolean isOperator(char c) {
        return c == '*' || c == '/' || c == '+' || c == '-';
    }

    // 返回运算符的优先级
    private static int precedence(char operator) {
        if (operator == '*' || operator == '/') {
            return 2; // 乘除优先级高
        } else if (operator == '+' || operator == '-') {
            return 1; // 加减优先级低
        }
        return -1; // 无效的运算符
    }

    // 根据运算符对两个分数进行运算
    private static BigFraction applyOperator(char operator, BigFraction b, BigFraction a) {
        try {
            switch (operator) {
                case '+': return a.add(b); // 加法
                case '-': return a.subtract(b); // 减法
                case '*': return a.multiply(b); // 乘法
                case '/':
                    if (b.equals(BigFraction.ZERO)) {
                        System.err.println("Division by zero is not allowed."); // 除以零的错误处理
                        return null;
                    }
                    return a.divide(b); // 除法
                default:
                    throw new IllegalArgumentException("Invalid operator: " + operator); // 无效运算符
            }
        } catch (NullArgumentException e) {
            System.err.println(e.getMessage()); // 处理空参数异常
            return null;
        }
    }
}

效能分析

性能分析图


模块接口

测试运行

运行结果

  • 输入100个问题数,输入范围是10,返回客户端压缩包,压缩包里面是exercise文件和answer文件


项目小结

  • 小组合作不仅深化了对我们编程技术的理解,更学会了团队协作的重要性。通过共同面对挑战、讨论解决方案,我们体会到了集思广益的力量。

  • 遇到了不少挑战,其中最大的难点在于确保运算题目的多样性和难度控制。如何让生成器既能涵盖加、减、乘、除等基本运算,又能根据年级调整难度,成为我们重点攻克的问题。
    此外,编程过程中遇到的逻辑错误和算法优化也是不容忽视的难点。通过不断试错与调整,我们学会了如何更高效地沟通与合作,最终克服了这些障碍。

  • 这段经历不仅增长了知识,还培养了我们的逻辑思维能力和耐心,让我们深刻理解了合作的力量,面对难题时的坚持与探索让我们收获满满,为未来学习和工作奠定了坚实的基础。

标签:分数,结对,return,String,项目,int,带分数,运算符
From: https://www.cnblogs.com/hyy02/p/18419346

相关文章

  • 某房地产集团搭建员工培训体系项目纪实
    某房地产集团搭建员工培训体系项目纪实——完善员工培训体系,提高培训效果【客户行业】房地产行业【问题类型】培训体系【客户背景】某房地产公司隶属于某大型央企,主营业务涵盖房产开发、物业管理等房地产全产业链。依托央企的品牌和实力,充分发挥产业链协同、城市综合开发......
  • 某国有投资集团用人机制改革项目成功案例纪实
    某国有投资集团用人机制改革项目成功案例纪实——引入淘汰机制,优化用人机制,有效传导压力【客户行业】国有企业;金融行业【问题类型】用人机制改革【客户背景】南方某集团,是面向工业领域的综合类国有资本投资公司,集团员工数万人,部门几十个,拥有多家子公司,涉及投资运营领域广......
  • 【项目案例】嵌入式Linux比较好的10+练手项目推荐,附项目文档/源码/视频
    后台私信小雯老师,回复“嵌入式Linux项目”,免费获取以下所有项目配套源码及文档。练手项目推荐 1 智能猫眼项目功能介绍:1.人脸识别:基于百度专业的深度学习算法和海量数据训练可进行人脸识别,轻松知晓访客身份;2.智能报警:实时检测非法闯入,可以自动布防,当触发警报时实时报警,最短时间......
  • 如何在CMakeList项目中集成GNU Autotools 构建模块
    背景:我有三个工具A,B,C,其中A,B是原先MakeFile编译的工具,C是原先GNUAutotools自动编译的工具。现在希望使用CMakeList统一构建,我的目录如下:||–A|-----/src|-----CMakeList.txt|–B|-----/src|-----CMakeList.txt|–C|-----autoTool|–CMakeList.txt想要起到的效......
  • OA项目之用户管理
    1.用户管理1.1.后台接口定义分页查询用户接口定义,支持条件模糊查询;新增用户接口定义;编辑用户接口定义;删除用户接口定义;1.2.前端用户管理实现1.2.1.分页查询页面初始化<!--数据表格--><tablestyle="margin-top:-15px;"id="tb_user"lay-filter="t......
  • 【项目案例】物联网比较好的10+练手项目推荐,附项目文档/源码/视频
    练手项目推荐 1 智能小车项目功能介绍:本项目由三部分组成:应用端(微信小程序)、设备端(Hi3861)、驱动端(UPS)。1.应用端,采用微信小程序作为应用端控制界面。在开发微信小程序端之前,需要熟悉JavaScript语言、CSS语言、XML语言和JSON语言。在微信小程序端的控制小车界面中需要输入......
  • 结对项目
    结对项目项目成员及github地址郭人诵github地址:https://github.com/EIiasK/Eliask何其浚github地址:https://github.com/hugh143/hugh143这个作业属于哪个课程https://edu.cnblogs.com/campus/gdgy/CSGrade22-34这个作业要求在哪里https://edu.cnblogs.c......
  • 说一说AI副业变现赚钱的那些小项目 每一个都能从无到有
    随着AI技术的飞速发展,它已经渗透到艺术设计行业,彻底改变了设计师们的工作方式。虽然众多网络公司已将AI工具纳入工作流程,提升了工作效率并降低了成本,但一些设计师也因AI的替代作用面临失业风险。最近很多小伙伴们讨论最多的话题是,我们这些普通人如何利用AI绘画技术来赚点小......
  • 没有项目经验,如何快速转行 AI产品经理?
    先上结论:要快速转行,需要了解AIGC,并丰富项目经验。AIGC是什么**首先需要了解AIGC基本概念、涉及的技术基础、应用场景和局限性。**之所以需要具备这些知识,是因为实现AIGC产品必然会涉及相应的AI技术,如果AIGC产品经理不了解相关概念,就不能很好的完成AIGC项目的管理。当然,AI......
  • 黑马PM-基础入门-项目立项
    项目方案可行性分析产品规划立项评审......