结对作业

软件工程结对作业:自动生成小学四则运算题目的命令行程序

这个作业属于哪个课程 软件工程2024 - 广东工业大学
这个作业要求在哪里 软件工程2024 - 班级博客
这个作业的目标 结对双人开发自动生成小学四则运算题目的命令行程序
姓名 学号
吴达武 3122004405
张兴裕 3122004415

PSP表格

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

一、需求分析

看题目可以看出我们要设计两个功能:

  • 实现表达式生成,并计算表达式,将表达式和答案写入文件中。
  • 给定题目表达式,计算给定的表达式与给定的答案文件进行校对,加校对结果写入文件。

二、模块接口的设计与实现过程

程序流程图

模块接口的设计与说明

这个程序主要是表达式的计算,我们利用队列将表达式转换成后缀表达式,再利用栈、队列计算,由于有分数的出现,我们编写了一个Fraction类来实现分数运算。

对于整个程序而言,独占时间最多的用户函数是InfixToPostfixAndEvaluateUtils(),这也不难解释,因为对于这个程序来说,每个函数都是O(n)级别的,InfixToPostfixAndEvaluateUtils()这个函数是将中缀表达式转换成后缀表达式,并计算结果,其中利用栈、队列会占用更多的内存空间,并且,不管使用生成表达式功能还是校对功能都要以调用这个工具。

三、代码说明

中缀表达式为后缀表达式的原理如下:

  • 从左到右扫描中缀表达式的每个元素。
  • 如果遇到操作数(数字),直接将其输出到后缀表达式中。
  • 如果遇到运算符,分两种情况处理:
  • 如果栈为空,直接将运算符入栈。
  • 如果栈不为空,比较当前运算符与栈顶运算符的优先级:
  • 如果当前运算符优先级高于栈顶运算符,直接入栈。
  • 如果当前运算符优先级低于或等于栈顶运算符,将栈顶运算符出栈并输出到后缀表达式中,重复比较直到当前运算符可以入栈。
  • 当所有元素扫描完成后,将栈中剩余的运算符依次出栈并输出到后缀表达式中。
// 将中缀表达式转换为后缀表达式
    public static Queue<String> infixToPostfix(String exp) {
        Queue<String> result = new LinkedList<>();
        Stack<Character> stack = new Stack<>();

        for (int i = 0; i < exp.length(); i++) {
            char c = exp.charAt(i);
            if (Character.isDigit(c)) {
                int p;

                for(p = i; p < exp.length() && Character.isDigit(exp.charAt(p)); ++p) {
                }
                result.add(exp.substring(i, p));
                //读取多位数字时要先存住,划分成一个string
                i = p-1;
            } else if (c == '(') {
                stack.push(c);
            } else if (c == ')') {
                while (!stack.isEmpty() && stack.peek() != '(') {
                    result.add(String.valueOf(stack.pop()));
                }
                stack.pop();
            } else {
                while (!stack.isEmpty() && precedence(c) <= precedence(stack.peek())) {
                    result.add(String.valueOf(stack.pop()));
                }
                stack.push(c);
            }
        }
        while (!stack.isEmpty()) {
            result.add(String.valueOf(stack.pop()));
        }
        return result;
    }

    // 方法确定运算符的优先级
    private static int precedence(char op) {
        if (op == '+' || op == '-') {
            return 1;
        } else if (op == '×' || op == '÷') {
            return 2;
        }else if(op == '/'){
            return 3;
            //‘/‘斜杠优先级更加高不然 1÷1/3 则会错误
        }
        return 0;
    }
    // 方法检查字符是否为运算符
    public static boolean isOption(char c){
        return c == '+' || c == '-' || c == '×' || c == '÷'|| c == '/';
    }

带分数转换假分数原理如下:

根据变量f的取值,可能在处理带分数和假分数的转换。当f为-2时,可能在处理带分数的整数部分;当f为-1时,可能在处理带分数的分子部分,当f为0是处理分母部分;其他情况可能在处理假分数或其他操作。

 for(; ((str3 = file1.readLine()) != null)&&((str4 = file2.readLine()) != null); ++j) {
            System.out.println(str3);
            StringBuilder tmp= new StringBuilder();
            int x1=-1,x2=-1,x3=-1;
            int f=-2;
            //由于我们的计算都是通过假分数的,此处将带分数都转化为假分数,只要通过读取'和/ 进行条件判断,在O(n)的时间内将带分数都转化为假分数。
            for(int i=0;i< str3.length();i++){
                if(isDigital(str3.charAt(i))){
                    if(f==-2){
                        if(x1==-1){
                            x1=0;
                        }
                        x1=x1*10+str3.charAt(i)-'0';
                    }else if(f==-1){
                        if(x2==-1){
                            x2=0;
                        }
                        x2=x2*10+str3.charAt(i)-'0';
                    }else {
                        if(x3==-1){
                            x3=0;
                        }
                        x3=x3*10+str3.charAt(i)-'0';
                    }
                }else if(str3.charAt(i)=='\''){
                    f=-1;
                }else if(f==-1 && str3.charAt(i)=='/'){
                    f=0;
                }else{
                    if(f==0){
                        int p1=x1*x3+x2,p2=x3;
                        tmp.append(p1);
                        tmp.append('/');
                        tmp.append(p2);
                    }else if(f==-2){
                        if(x1!=-1) {
                            tmp.append(x1);
                        }
                    }
                    tmp.append(str3.charAt(i));
                   x1=-1;
                   x2=-1;
                   x3=-1;
                   f=-2;
                }
            }
            System.out.println(tmp);
            Queue<String> postfixExp =InfixToPostfixAndEvaluateUtils .infixToPostfix(tmp.toString());
            Fraction ans1 =  InfixToPostfixAndEvaluateUtils .calculate(postfixExp);
            String str5 ="";
            str5+=j;
            str5+=". ";
            str5 += ans1.transferFraction(ans1);
            System.out.println(str5);
            if (str5.equals(str4)) {
                correct.add(j);
            } else {
                wrong.add(j);
            }
        }

四、测试运行

功能选择

表达式生成




校对成绩





计算结果单元测试

五、总结

万事开头难,我们写程序的时候就是这样,在思考每个功能的时候都觉得毫无头绪,甚至认为不是我们能实现的,但好在通过两人密切合作,减轻个人压力。两人共同承担任务,可以互相监督和支持,确保任务按时完成并达到预期目标。

posted @ 2024-03-26 13:10  Five_v_five  阅读(14)  评论(1编辑  收藏  举报