首页 > 其他分享 >结对项目:实现自动生成小学四则运算题目

结对项目:实现自动生成小学四则运算题目

时间:2023-09-25 12:56:19浏览次数:30  
标签:结对 题目 四则运算 List System println new 表达式 out

这个作业属于哪个课程 计科21级12班
这个作业要求在哪里 结对项目
这个作业的目标 熟悉结对项目的的合作方法与模式

团队成员信息

姓名 学号
刘晋延 3121004832
张建文 3121004845

PSP表格

PSP2.1 Personal Software Process Stages 预估耗时(分钟) 实际耗时(分钟)
Planning 计划 40 60
-Estimate -估计这个任务需要多少时间 1600 1930
Development 开发 1200 1420
-Analysis -需求分析 (包括学习新技术) 300 300
-Design Spec -生成设计文档 60 80
-Design Review -设计复审 40 20
-Coding Standard -代码规范 (为目前的开发制定合适的规范) 100 100
-Design -具体设计 200 300
-Coding -具体编码 400 520
-Code Review -代码复审 100 100
Test 测试(自我测试,修改代码,提交修改) 400 450
-Reporting -报告 150 170
-Test Report -测试报告 150 130
-Size Measurement -计算工作量 50 80
-Postmortem & Process Improvement Plan -事后总结, 并提出过程改进计划 50 70
合计 1600 1930

接口的设计和实现

1、设计思路

该次项目实现了全部需求1~9,根据分析,整体功能总共需要实现三个方面的功能:生成四则运算式,计算结果,文件读写。

  • 生成四则运算式
    • 运算式需要考虑是否重复,是否出现除数为0和运算过程出现负数的情况,均利用二叉树来检查。
    • 分数需要单独写一个方法进行随机。
  • 计算结果
    • 采用后缀表达式计算
    • 因为生成的四则运算式为中缀表达式,故还需要先转化为后缀表达式。
  • 文件读写
    • 文件读写均调用包里的接口,比较简单

2、整体流程

需要根据输入的参数分辩具体实现的功能。
-n:指定生成题目数量
-r:指定题目中数字范围
-e:指定输入的题目文件路径
-a:指定输入的答案文件路径

3、类

  • 生成四则运算式
    • BinaryTree.java :主要用于二叉树的操作,如建树等;基于二叉树判断重复的算法也在此处。
    • Generate.java :主要用于四则运算式的生成,其内包含生成分数,以及生成整合四则运算式及答案的方法。
    • TreeNode.java :定义了二叉树的节点,包含具体检测减法除法以及由树转换后缀表达式的方法。
  • 计算结果
    • ComputeFourRule.java:含有结果的计算和中缀表达式转换后缀表达式的方法。
    • Fraction.java:该类主要对分数进行操作,分割分子与分母,以及标准化分数的格式。
  • 文件读写
    • Determine.java:读入题目与答案,并输出对错结果。
    • read.java:文件读写
  • 其他
    • Main.java:main方法所在的类
    • MyException.java:自定义异常类,用于抛出异常信息

4、关键代码

1、判断四则运算式重复

主要通过后缀表达式所构建的二叉树判断,根据两个式子的二叉树是否能通过交换加与乘节点的左右子树变成同一个二叉树来判断。代码如下:

    public static boolean isSameTree(TreeNode p, TreeNode q) {
        if (p == null && q == null) {
            return true;
        } else if (p == null || q == null) {
            return false;
        } else if (!p.getName().equals(q.getName())) {
            return false;
        } else {
            if(p.getName().equals("+") || p.getName().equals("*")){//加法与乘法可交换节点
                return (isSameTree(p.getLeft(), q.getLeft()) && isSameTree(p.getRight(), q.getRight()))||isSameTree(p.getLeft(),q.getRight() ) && isSameTree(p.getRight(),q.getLeft() );
            }
            return isSameTree(p.getLeft(), q.getLeft()) && isSameTree(p.getRight(), q.getRight());
        }
    }

2、判断除法与减法

除法与减法的判断逻辑相似,都是遍历二叉树,找到对应除法与减法的节点,根据其左右子树判断。代码如下:

public boolean postOrderDivide(){
        //遍历检查除法
        boolean  statel=true;
        boolean stater=true;
        if(this.left!=null){
           statel= this.left.postOrderDivide();
        }
        if(this.right!=null){
            stater= this.right.postOrderDivide();
        }
        if(!(statel&&stater)) return false;
        if(this.name.equals("÷")){//除法判断右子树对应式子值是否会为0
            List<String> Right=new ArrayList<>();
            this.right.postOrder(Right);
            return !ComputeFourRule.Compute(Right).equals("0");
        }
        else{
            return true;
        }


    }
public boolean postOrderSubtraction(){
        //遍历检查减法
        boolean  statel=true;
        boolean stater=true;
        if(this.left!=null){
            statel=this.left.postOrderSubtraction();
        }
        if(this.right!=null){
            stater=this.right.postOrderSubtraction();
        }
        if(!(statel&&stater)) return false;
        if(this.name.equals("-")){//计算减法左右子树对应式子的值比较大小
            List<String> Left=new ArrayList<>();
            List<String> Right=new ArrayList<>();
            this.left.postOrder(Left);
            this.right.postOrder(Right);
            String leftnumber=ComputeFourRule.Compute(Left);
            String rightnumber=ComputeFourRule.Compute(Right);
            int[] number1=new Fraction().SplitNumber(leftnumber);
            int[] number2=new Fraction().SplitNumber(rightnumber);
            return number1[0] * number2[1] >= number2[0] * number1[1];
        }
        else return true;
    }

3、中缀表达式转为后缀表达式

  • 主要流程为:
    • 从左到右读入中缀表达式
    • 读入操作数直接输入后缀表达式
    • 读入左括号直接入栈
    • 读入右括号直接出栈,并将出栈运算符送入后缀表达式,直到左括号出栈
    • 读入运算符,若栈空,直接入栈。
      若栈非空,判断栈顶操作符,若栈顶操作符优先级低于该操作符,该操作符入栈;否则一直出栈,并将出栈字符依次送入后缀表达式,直到栈空或栈顶操作符优先级低于该操作符,该操作符再入栈。
public static List<String> SuffExpression(List<String> list){
        //转换为后缀表达式
        List<String> suffexpression= new ArrayList<>();
        Stack<String> stack= new Stack<>();
        for(int i=0;i<list.size();i++){
            String suff=list.get(i);
            if(suff.equals("(")) {
                stack.push(suff);
            }else if(suff.equals(")")){
                while (!stack.peek().equals("("))
                    suffexpression.add(stack.pop());
                stack.pop();
            }else if(suff.equals("*")||suff.equals("÷")){
                if(!stack.empty()){
                    while (stack.peek().equals("*")||stack.peek().equals("÷")) {
                        suffexpression.add(stack.pop());
                        if(stack.empty())
                            break;
                    }
                }
                stack.push(suff);
            }else if(suff.equals("+")||suff.equals("-")){
                if(!stack.empty()){
                    while (stack.peek().equals("+")||stack.peek().equals("-")||stack.peek().equals("*")||stack.peek().equals("÷")){
                        suffexpression.add(stack.pop());
                        if(stack.empty())
                            break;
                    }
                }
                stack.push(suff);
            }else {
                suffexpression.add(suff);
            }
        }
        while (!stack.empty()){
            suffexpression.add(stack.pop());
        }
        return suffexpression;
    }

4、计算结果

从左到右遍历后缀表达式的每个数字和符号,遇到是操作数就进栈,遇到是符号,就将处于栈顶两个操作数出栈,进行运算,运算结果进栈,一直到最终获得结果。因为存在分数,故计算需要单独处理。

public static String Compute(List<String> list){
        String result;
        Stack<String> stack1= new Stack<>();
        int leftnumber;
        int rightnumber;
        int[] number1=new int[2];
        int[] number2=new int[2];
            for(int i=0;i<list.size();i++){
                String suff=list.get(i);
                if (suff.equals("+")) {
                    number2=new Fraction().SplitNumber(stack1.pop());
                    number1=new Fraction().SplitNumber(stack1.pop());
                    leftnumber=number1[0]*number2[1]+number2[0]*number1[1];
                    rightnumber=number1[1]*number2[1];
                    stack1.push(leftnumber+"/"+rightnumber);
                } else if (suff.equals("-")) {
                    number2=new Fraction().SplitNumber(stack1.pop());
                    number1=new Fraction().SplitNumber(stack1.pop());
                    leftnumber=number1[0]*number2[1]-number2[0]*number1[1];
                    rightnumber=number1[1]*number2[1];
                    stack1.push(leftnumber+"/"+rightnumber);
                } else if (suff.equals("*")) {
                    number2=new Fraction().SplitNumber(stack1.pop());
                    number1=new Fraction().SplitNumber(stack1.pop());
                    leftnumber=number1[0]*number2[0];
                    rightnumber=number1[1]*number2[1];
                    stack1.push(leftnumber+"/"+rightnumber);
                }else if(suff.equals("÷")){
                    number2=new Fraction().SplitNumber(stack1.pop());
                    number1=new Fraction().SplitNumber(stack1.pop());
                    leftnumber=number1[0]*number2[1];
                    rightnumber=number1[1]*number2[0];
                    stack1.push(leftnumber+"/"+rightnumber);
                }else {
                    stack1.push(suff);
                }
            }
            result=stack1.pop();
        result=new Fraction().SimplestFraction(result);
        return result;
    }

测试运行

1、BinaryTree类

  • 主要测试
    • 检查四则式的重复功能
    • 检查除法的除数是否为0的方法
    • 检查减法是否会产生负数
      测试代码如下:
@Test
   void checkRepetition() {
       //检查四则式的重复功能
       List<String> a= Arrays.asList("1","2","+","3","+");
       List<String> b=Arrays.asList("3","2","1","+","+");
       List<String> c=Arrays.asList("3","2","+","1","+");
       System.out.println(BinaryTree.CheckRepetition(a,b));
       System.out.println(BinaryTree.CheckRepetition(a,c));
   }

   @Test
   void checkdivide(){
       //检查除法的除数是否为0的方法
       List<String> a=Arrays.asList("(","8","*","7",")","÷","(","5","-","4",")");
       List<String> b=Arrays.asList("(","8","*","7",")","÷","(","5","-","5",")");
       System.out.println(BinaryTree.CheckDivide(ComputeFourRule.SuffExpression(a)));
       System.out.println(BinaryTree.CheckDivide(ComputeFourRule.SuffExpression(b)));
   }
   @Test
   void checksubtraction(){
       //检查减法是否会产生负数
       List<String> a=Arrays.asList("(","8","*","7",")","÷","(","5","-","6",")");
       List<String> b=Arrays.asList("(","8","*","7",")","÷","(","5","-","4",")");
       System.out.println(BinaryTree.CheckDivide(ComputeFourRule.SuffExpression(a)));
       System.out.println(BinaryTree.CheckDivide(ComputeFourRule.SuffExpression(b)));
   }
  • 测试结果

  • 代码覆盖率

2、ComputeFourRule类

  • 主要测试
    • 计算结果
    • 转换为后缀表达式
 void suffExpression() {
        //转换为后缀表达式
        List<String> a=Arrays.asList("1","+","2","+","3");
        List<String> b=Arrays.asList("(","8","*","7",")","÷","(","5","-","4",")");
        a=ComputeFourRule.SuffExpression(a);
        b=ComputeFourRule.SuffExpression(b);
        System.out.println(a);
    }

    @Test
    void compute() {
        //计算结果
        List<String> a= Arrays.asList("1","÷","6","+","2'7/10","*","7");
        a=ComputeFourRule.SuffExpression(a);
        System.out.println(ComputeFourRule.Compute(a));
    }
  • 测试结果

  • 代码覆盖率

该处代码覆盖率主要跟所涉及的运算种类有关

3、Fraction类

  • 主要测试
    • 分割分子分母
    • 转换分数格式
 @Test
    void splitNumber() {
        //测试分割分子分母
        int[] a=new Fraction().SplitNumber("2");
        System.out.println("分子:"+a[0]+" 分母:"+a[1]);
        int[] b=new Fraction().SplitNumber("2'2/3");
        System.out.println("分子:"+b[0]+" 分母:"+b[1]);
        int[] c=new Fraction().SplitNumber("7/8");
        System.out.println("分子:"+c[0]+" 分母:"+c[1]);
    }

    @Test
    void simplestFraction() {
        //测试转换分数格式
        System.out.println(new Fraction().SimplestFraction("10/3"));

    }
  • 测试结果

  • 代码覆盖率

4、Generate类

  • 主要测试
    • 式子与分数的生成
    • 整合后的多个式子生成与计算
@org.junit.jupiter.api.Test
    void creat() {
        System.out.println(String.join(" ",Generate.Creat(10)));
    }

    @org.junit.jupiter.api.Test
    void creatFraction() {
        System.out.println(Generate.CreatFraction(10));
    }

    @Test
    void EquationCreateTest(){
        //生成试题
        List<List<String>> a=Generate.EquationCreate(10,10);
       for (List<String> b:a){
            System.out.println(String.join(" ",b));
        }
    }
    @Test
    void AnswerTest(){
        //计算答案
        List<List<String>> a=Generate.EquationCreate(10,10);
        List<String> b=Generate.Answer(a);
        for (List<String> c:a){
            System.out.println(String.join(" ",c));
        }
        for(String d:b){
            System.out.println(d);
        }
    }
  • 测试结果
  • 代码覆盖率

5、参数异常输入测试


如图,当参数输入存在错误时会给出提示。

6、正常功能测试

  • 1、生成10道范围为10的题目

    结果如下:
  • 2、传入文件计算对错
    传入文件

    结果如下

效能分析


如图,占用最大的内存为TreeNode类,此为二叉树节点类,主要原因:生成四则运算需要遍历所有题目生成二叉树来判断重复,故当题目数量增大时,该类占用内存会增大

项目小结

  • 项目分工
    • 刘晋延:实现四则运算式的生成与运算式重复检验,以及博客的整理。
    • 张建文:实现四则运算式的计算与文件的读写,以及需求9中对真错的判断与输出。

标签:结对,题目,四则运算,List,System,println,new,表达式,out
From: https://www.cnblogs.com/liujinyan/p/17727700.html

相关文章

  • 结对项目:用Python实现四则运算
    这个作业属于哪个课程计科1/2班这个作业要求在哪里结对项目这个作业的目标实现一个自动生成小学四则运算题目的命令行程序团队成员姓名学号梁昊东3121005000李铭伟3121004145github链接:https://github.com/e1ecb0t/e1ecb0t/tree/main/cacul......
  • 青少年CTF Web题目 - 哥哥打篮球
    题目链接:青少年CTF训练平台|原中学生CTF平台|青少年CTF(qsnctf.com)打开后是这样的先查看一下源代码,使用快捷键Ctrl+U,然后查看一下这个main.js文件直接搜索if判断语句,发现JSfuck编码,并且发现主要部分乱码了那先看看jsfuck解码的明文是什么,直接放到控制台回车,发现......
  • 2022新领军一试部分题目及解答
    2022新领军一试部分题目及解答小学渣​爱数学的初三菜鸡一枚前言:本文章仅用于记录作者本人思考的解答,看个乐子就好(初二牲)1.(1)求 I_n=\displaystyle\int_{-1}^{1}x^n\sqrt{1-x^2}\mathrm{d}x\;\;\;\;\;\;\; (2)求 \displaystyle\sum_{n=1}^{+\i......
  • 实现一个自动生成小学四则运算题目的命令行程序
    这个作业属于哪个课程21计科34班这个作业要求在哪里结对项目这个作业的目标自动生成四则运算题目、检查四则运算结果https://github.com/jack1349/jackchen1349/tree/master/31210052041、PSP表格PSP2.1PersonalSoftwareProcessStages预估耗时(分钟)实......
  • PPT题目
    1//生成一千个随机数2publicclassLinearCongruentialGenerator{3privatestaticfinallongMODULUS=2147483647;//2^31-14privatestaticfinallongMULTIPLIER=75;5privatestaticfinallongINCREMENT=0;67privatelo......
  • 中小学生数学卷子自动生成程序-结对编程队友互相评价
    中小学数学卷子自动生成程序——结队编程队友互相评价 一、功能实现1、运行程序,显示输入用户姓名及密码,输入姓名和密码之后,自动核验账号密码是否匹配,不匹配的话则要求重新输入账号密码2、在输入账号密码之后登陆成功,登陆成功之后,会要求输入需要生成的试卷的题目数量,题目数量......
  • 结对编程博客
    结对编程队友:软件2103黄晖凯项目结构如下图通过项目结构可以清晰的看出每个JAVA类的实现功能,便于查阅和修改代码,这是优点。 为了满足个人项目要求建立的抽象类,过于简单抽象, 在主方法后面加上throwsIOException,确保在出现异常的情况下不会崩溃,无法处理,使得代码更加健康。......
  • HNU 结对编程 对队友代码的分析 中小学数学卷子自动生成程序
    基本功能实现一、主要内容认真学习和阅读同伴的代码,分析优劣。二、题目要求个人项目:中小学数学卷子自动生成程序用户:小学、初中和高中数学老师。功能:1、命令行输入用户名和密码,两者之间用空格隔开(程序预设小学、初中和高中各三个账号,具体见附表),如果用户名和密码都正确,将根......
  • 软件工程导论——对结对伙伴袁永杰的个人项目评价
    一前言   很感谢老师安排的这次互评,我从伙伴的代码中得到了一些收获,也对Java编程有了更多的理解,思维也变得更加清晰。同伴选择的也是Java,基于面向对象的思想,在进行评价的同时我也会学习他的优点,不断努力进步。二项目需求与评分标准用户:小学、初中和高中数学老师。功......
  • 与结对队友的个人项目互评
    与我结对的队友是木拉迪力.艾海提同学,接下来我来分析一下他的个人项目:#include<iostream>#include<string>#include<fstream>#include<ctime>#include<cstdlib>usingnamespacestd;classTeacher{public:Teacher();Teacher(stringusername,stringpwd,str......