结对项目
结对项目
软件工程 | <https://edu.cnblogs.com/campus/gdgy/informationsecurity1812/> |
---|---|
作业要求 | <https://edu.cnblogs.com/campus/gdgy/informationsecurity1812/homework/11157> |
作业目标 | - PSP记录 - 项目代码实现 - GitHub - 性能测试 |
队友
姓名 | 学号 | GitHub地址 |
---|---|---|
赖晋启 | 3118005366 | <https://github.com/gdut-jq/gdut-jq> |
李业 | 3118005369 | <https://github.com/PURSUE2/3118005369> |
PSP表
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 10 | 5 |
· Estimate | · 估计这个任务需要多少时间 | 10 | 5 |
Development | 开发 | 530 | 555 |
· Analysis | · 需求分析 (包括学习新技术) | 20 | 15 |
· Design Spec | · 生成设计文档 | 10 | 10 |
· Design Review | · 设计复审 | 10 | 5 |
· Coding Standard | · 代码规范 (为目前的开发制定合适的规范) | 10 | 5 |
· Design | · 具体设计 | 10 | 10 |
· Coding | · 具体编码 | 240 | 300 |
· Code Review | · 代码复审 | 120 | 60 |
· Test | · 测试(自我测试,修改代码,提交修改) | 120 | 90 |
Reporting | 报告 | 30 | 55 |
· Test Repor | · 测试报告 | 30 | 45 |
· Size Measurement | · 计算工作量 | 10 | 10 |
· Postmortem & Process Improvement Plan | · 事后总结, 并提出过程改进计划 | 10 | 10 |
. 合计 | 570 | 615 |
设计实现
主类( Myapp.class )
-
- main(String args[]):接收数据。
查重类( DuplicateCheckUtil.class )
-
- public String reverse(String str):对传入的字符串反转后返回,用于方便判断1+2=2+1这种重复情况。
-
- public boolean isDuplicate(Map<String, Set
> map, String que, String answer):该类的核心部分,通过对不同形式的题目进行判断,若答案相同且题目重复,则返回true。
- public boolean isDuplicate(Map<String, Set
生成题目和答案类( Creat.class )
-
- randomNumber(int min,int max):生成随机数,范围 min~max-1 。
-
- Symbol():随机生成运算符。
-
- operation(char o,int x1,int x2,int y1,int y2):四则运算。
-
- dataGeneration(int a,int b):把假分数化为真分数或整数。
-
- fracReduction(int numerator, int denominator):分子分母化简。
-
- Q1(int x1,int x2,int y1,int y2,char o1):生成两个数的四则运算题目。
-
- Q2(int x1,int x2,int y1,int y2,int z1,int z2,char o1,char o2,int op):生成三个数的四则运算题目。
-
- Data(int n, int r):随机生成运算数据的分子和分母。
以文件输出类( OutToFile.class )
-
- sysout(int n,int r):题目和答案以文件形式输出。
代码说明
四则运算部分
//通过分子分母间运算实现四则运算
public static String operation(char o,int x1,int x2,int y1,int y2){
String r = null;
int m=x2*y2;
int x3=x1*y2;
int y3=x2*y1;
if(o=='+'&&x3+y3>=0)r=dataGeneration(x3+y3,m);
else if(o=='-'&&x3-y3>=0)r=dataGeneration(x3-y3,m);
else if(o=='×'&&x1*y1>=0)r=dataGeneration(x1*y1,m);
else if(o=='÷'&&y3>0&&x3>=0)r=dataGeneration(x3,y3);
return r;
}
化简部分
//通过辗转相除法把真分数化为最简分数
public static String fracReduction(int numerator, int denominator) {
//找到最大公约数,然后分别处以最大公约数
int m = numerator;
int n = denominator;
int r;
while (numerator > 0){
r = denominator % numerator;
denominator = numerator;
numerator = r;
}
return m/denominator + "/" + n/denominator;
}
查重部分
- DuplicateCheckUtil类是对查重功能的实现,该类共包括2个方法:
查重部分涉及的不同形式问题对比如下:
为了提高该程序的性能,我们两个伙伴讨论下,决定将问题和答案放在map里面,答案作为键,相同答案的问题集合作为值,形式为:map<String, Set
如果答案不同,那题目自然也不重复;答案相同,题目则有可能重复。用map<String, Set
这与直接和所有已生成问题进行比较的方法相比,自然少了很多不必要的操作。而且该map是由外界传入的,调用该方法的位置只需要每成功生成一道不重复的题目,就把该题目更新到map中。若是在查重方法中生成这个map,会多出很多累赘代码以及多次循环带来的性能低下。
实现查重功能是通过左结合规则、括号优先结合以及乘除优先来实现的。
例如:(1+2)+3 与 3+(2+1),因为括号内运算符都为 + 以及运算数都为1和2,且括号外运算符和运算数也都一样,故这两个式子是重复的。
//que:(1+2)+3 ; question:1+(2+3)
if(question.charAt(4)=='('){
if(question.charAt(0)==que.charAt(10) && question.charAt(2)==que.charAt(8)){
if(question.charAt(7)==que.charAt(3)){
//(1+2)+3 = 3+(1+2) && (1+2)+3 = 3+(2+1)
if((question.charAt(5)==que.charAt(1) && question.charAt(9)==que.charAt(5)) || (question.charAt(9)==que.charAt(1) && question.charAt(5)==que.charAt(5))){
return true;
}
}
}
}
单元测试
//以5为倍数生成10到10000道题和答案
import org.junit.jupiter.api.Test;
class OutToFileTest {
@Test
void sysout() {
OutToFile outToFile = new OutToFile();
int i = 10;
while (i < 100001) {
outToFile.sysout(i, 50);
i *= 5;
}
}
}
- 测试结果
性能分析
该性能测试是在生成30000条以上的问题的情况下进行的。
内存占用
由图可以看出该程序内存占用主要是byte数组和char数组引起的,这两部分与生成题目部分和输出到文件有关。
main 函数耗时
由图可知,在生成3万条问题下,执行该程序的时间也就5秒多一点,效率还是可以的。
CPU 及堆
由下图可看出该程序对cpu占用不是很大,且随时间线逐渐减小对cpu的占用。
而堆的部分,最大占用也仅达到堆大小的1/5,且达到该数值后使用的堆空间又得到释放。