结对作业
项目 | 内容 |
---|---|
这个作业属于哪个课程 | 软件工程 |
作业要求 | 作业要求 |
作业目标 | 生成四则运算生成器 |
-
队伍
3119005425 莫奇易
3119005435 谢国浩
一.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个半天,要想抓紧提升还是要下不少功夫,掉不少头发。总而言之,这次项目还是学到了好多东西,还得亏浩宝帮忙进行后面的单元测试性能分析等,又省下了不少睡觉的时间。下次再接再厉。