结对作业

项目 内容
这个作业属于哪个课程 软件工程
作业要求 作业要求
作业目标 生成四则运算生成器

一.PSP表格

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

二.性能分析




三.实现类和流程

程序流程图

关键代码和分析

1.通过Generation类中的GenerateExp()方法实现随机运算表达式的生成,其中分别调用了GenerateNum()和Generate()方法随机生成运算数以及运算符

点击查看代码
public String GenerateExp(int r) {
        String exp = "";
        int flag = (int) (Math.random() * 3);// 控制是否生成括号 以及生成括号的位置
        int i = (int) (Math.random() * 3) + 1; // 控制随机生成运算符的个数
        for (int j = 1; j <= i; j++) {
            if (flag == 0 && i >= 2) {//生成括号,位置在两个运算符的前面  或者在 三个运算符的前面
                if (j == 1) {
                    exp = "(" + GenerateNum(r) + GenerateOperator();
                } else if (j == 2) {
                    exp = exp + GenerateNum(r) + ")" + GenerateOperator() + GenerateNum(r);
                } else if (j == 3) {
                    exp = exp + GenerateOperator() + GenerateNum(r);
                }
            }
            if (flag == 1 && i >= 2) {//生成括号 位置在三个运算符时的中间 或者在 两个运算符时的后面
                if (j == 1) {
                    exp = GenerateNum(r) + GenerateOperator() + "(";
                } else if (j == 2) {
                    exp = exp + GenerateNum(r) + GenerateOperator() + GenerateNum(r) + ")";
                } else if (j == 3) {
                    exp = exp + GenerateOperator() + GenerateNum(r);
                }
            }
            if (i == 1) {
                exp = GenerateNum(r) + GenerateOperator() + GenerateNum(r);
            } else if (i == 2) {
                exp = GenerateNum(r) + GenerateOperator() + GenerateNum(r) + GenerateOperator() + GenerateNum(r);
            } else {
                exp = GenerateNum(r) + GenerateOperator() + GenerateNum(r) + GenerateOperator() + GenerateNum(r) + GenerateOperator() + GenerateNum(r);
            }
        }
        return exp;
    }

2.Calculation类中的toHouzhui方法将传入的中缀表达式转换为后缀表达式

点击查看代码
public String toHouzhui(String str) throws NumberFormatException, EmptyStackException {
        //将中缀表达式转化为后缀表达式
        StringBuilder houzhui = new StringBuilder();
        Stack<Character> zzstack = new Stack<>();

        for (int i = 0; i < str.length(); i++) {
            char tmp;
            char c = str.charAt(i);
            switch (c) {
                case '(':
                    zzstack.push(c);
                    break;
                case ')'://右括号弹出直到遇到左括号为止
                    while (!zzstack.empty()) {
                        tmp = zzstack.pop();
                        if (tmp == '(') {
                            break;
                        } else {
                            houzhui.append(" ");
                            houzhui.append(tmp);
                        }
                    }
                    break;
                case '+':
                case '-'://'+'和'-'只是遇到‘(’时才不会弹出栈内元素
                    houzhui.append(" ");
                    while (!zzstack.empty()) {
                        tmp = zzstack.pop();
                        if (tmp == '(') {
                            zzstack.push('(');
                            break;
                        }
                        houzhui.append(tmp);
                        houzhui.append(" ");
                    }
                    zzstack.push(c);
                    break;
                case '*':
                case '÷'://‘*’和'÷'需要和要进栈的元素进行优先级判断,将栈中优先级大的弹出
                    houzhui.append(" ");
                    while (!zzstack.empty()) {
                        tmp = zzstack.pop();
                        if (tmp == '*' || tmp == '÷') {
                            houzhui.append(tmp);
                            houzhui.append(" ");
                        } else {
                            zzstack.push(tmp);
                            break;
                        }
                    }
                    zzstack.push(c);
                    break;
                default: //要是数字 空格的话直接加入后缀表达式中去
                    houzhui.append(c);
                    break;
            }
        }
        while (!zzstack.empty()) {//将剩下的运符依次弹出栈
            houzhui.append(" ");
            houzhui.append(zzstack.pop());
        }
        return houzhui.toString();
    }

3.Caculation类里面的calculate()方法实现对传入两个参数不同类型时的加减乘除运算

点击查看代码
 boolean flag1 = false;//用于判断x
        boolean flag2 = false;//用于判断y
        if (x.contains("/"))
            flag1 = true; // 分数 true
        if (y.contains("/"))
            flag2 = true; //分数 true

        int up1 = 1, up2 = 1, down1 = 1, down2 = 1, d1 = 0, d2 = 0;
        if (!flag1 && !flag2) {    //两整数之间
            up1 = Integer.parseInt(x);
            up2 = Integer.parseInt(y);
        }

        if (!flag1 && flag2) { //x 整数  y 分数
            up1 = Integer.parseInt(x);

            //处理 y 是分数的情况
            int f1 = -1;
            if (y.contains("'")) {// 是否是带分数
                f1 = y.indexOf("'");//f1 分割“‘ ”
                d2 = Integer.parseInt(y.substring(0, f1));//分数的整数部分
            }

            int f2 = y.indexOf("/");  //f2 分割 “ / ”
            up2 = Integer.parseInt(y.substring(f1 + 1, f2));
            down2 = Integer.parseInt(y.substring(f2 + 1));
            if (d2 < 0) {
                up2 = d2 * down2 - up2;
            } else {
                up2 = d2 * down2 + up2;
            }
        }

        if (flag1 && !flag2) {// x 分数 y 整数
            up2 = Integer.parseInt(y);

            //处理 x 是分数的情况
            int f1 = -1;
            if (x.contains("'")) {// 是否是带分数
                f1 = x.indexOf("'");//f1 分割“‘ ”
                d1 = Integer.parseInt(x.substring(0, f1));//分数的整数部分
            }
            int f2 = x.indexOf("/");  //f2 分割 “ / ”
            up1 = Integer.parseInt(x.substring(f1 + 1, f2));
            down1 = Integer.parseInt(x.substring(f2 + 1));
            if (d1 < 0) {
                up1 = d1 * down1 - up1;
            } else {
                up1 = d1 * down1 + up1;
            }
        }

        if (flag1 && flag2) { //x 和y 都是分数

            //处理 x 是分数的情况
            int f1 = -1;
            if (x.contains("'")) {// 是否是带分数
                f1 = x.indexOf("'");//f1 分割“‘ ”
                d1 = Integer.parseInt(x.substring(0, f1));//分数的整数部分
            }
            int f2 = x.indexOf("/");  //f2 分割 “ / ”
            up1 = Integer.parseInt(x.substring(f1 + 1, f2));
            down1 = Integer.parseInt(x.substring(f2 + 1));
            if (d1 < 0) {
                up1 = d1 * down1 - up1;
            } else {
                up1 = d1 * down1 + up1;
            }

            //处理 y 是分数的情况
            int f3 = -1;
            if (y.contains("'")) {// 是否是带分数
                f3 = y.indexOf("'");//f3 分割“‘ ”
                d2 = Integer.parseInt(y.substring(0, f3));//分数的整数部分
            }
            int f4 = y.indexOf("/");  //f4 分割 “ / ”
            up2 = Integer.parseInt(y.substring(f3 + 1, f4));
            down2 = Integer.parseInt(y.substring(f4 + 1));
            if (d2 < 0) {
                up2 = d2 * down2 - up2;
            } else {
                up2 = d2 * down2 + up2;
            }
        }

四.结果分析


Exercises.txt实现10000的随机生成:

Answers.txt保存文件,并实现了不生成负数的功能:

Grade.txt实现用户答题文件与答案文件进行比对:

五.单元测试

测试随机生成表达式类

测试约分和将假分数转带分数函数的各三个用例:

测试随机生成十个运算表达式用例:

测试计算类

测试中缀转后缀表达式的三个用例:

测试整数,真分数,带分数不同加减乘除下的五个用例:

测试通过后缀表达式 通过弹出栈顶结果的三个用例:

测试随机生成表达式类

测试约分和将假分数转带分数函数的各三个用例:

六.项目小结

浩:这次作业我全程划水,全靠奇易大佬带飞,希望下次作业我可以有自己独立完成的模块
易:软工作业真心折磨人,每次作业都少不了熬夜,虽然在上次项目的经验下整体思路流程清晰了不少,但代码编写能力还是很弱,遇到不会的得csdn个半天,要想抓紧提升还是要下不少功夫,掉不少头发。总而言之,这次项目还是学到了好多东西,还得亏浩宝帮忙进行后面的单元测试性能分析等,又省下了不少睡觉的时间。下次再接再厉。

posted @ 2021-10-26 01:18  bbq-carol  阅读(42)  评论(0编辑  收藏  举报