结对作业
结对作业
这个作业属于哪个课程 | 班级链接 |
---|---|
这个作业要求在哪里 | 作业要求 |
这个作业的目标 | 结对编程完成四则运算生成器 |
Github地址 | 3119005419 |
项目成员1 | 黎余明 3119005419 |
项目成员2 | 刘 煜 3119005424 |
1. PSP表格
PSP2.1 | Personal Software Process Stages | 预估耗时 | 实际耗时(分钟) |
---|---|---|---|
·Planning | · 计划 | 60 | 75 |
· Estimate | · 估计这个任务需要多少时间 | 30 | 20 |
·Development | 开发 | 400 | 840 |
· Analysis | · 需求分析 (包括学习新技术) | 150 | 180 |
· Design Spec | · 生成设计文档 | 60 | 50 |
· Design Review | · 设计复审 | 20 | 25 |
· Coding Standard | · 代码规范 (为目前的开发制定合适的规范) | 10 | 20 |
· Design | · 具体设计 | 50 | 60 |
· Coding | · 具体编码 | 150 | 400 |
· Code Review | · 代码复审 | 20 | 20 |
· Test | · 测试(自我测试,修改代码,提交修改) | 45 | 60 |
· Reporting | · 报告 | 85 | 95 |
· Test Repor | · 测试报告 | 20 | 20 |
· Size Measurement | · 计算工作量 | 15 | 15 |
· Postmortem & Process Improvement Plan | · 事后总结, 并提出过程改进计划 | 45 | 50 |
· 合计 | 1160 | 1930 |
2.效能分析
- 全部性能分析如下
3.设计实现过程
大致的过程是:
首先封装一个计算的工具类包括加减乘除,还包括一些分子分母的构建,之后在来一个可以解析并计算四则运算表达式(含括号),返回计算结果,其中要用到IO流就是读写文件。
4.代码说明
项目关键代码及其注释说明(其实就是注释,写注释好累)
public String calculate(String numStr) {
numStr = removeStrSpace(numStr); // 去除空格
// 如果算术表达式尾部没有‘=’号,则在尾部添加‘=’,表示结束符
if (numStr.length() > 1 && !"=".equals(numStr.charAt(numStr.length() - 1) + "")) {
numStr += "=";
}
// 检查表达式是否合法
if (!isStandard(numStr)) {
System.err.println("错误:算术表达式有误!");
return "0";
}
// 初始化栈
numberStack = new Stack<String>();
symbolStack = new Stack<Character>();
// 用于缓存数字,因为数字可能是多位的
StringBuffer temp = new StringBuffer();
// 从表达式的第一个字符开始处理
for (int i = 0; i < numStr.length(); i++) {
char ch = numStr.charAt(i); // 获取一个字符
if (isNumber(ch) || ch == '/') { // 若当前字符是数字
temp.append(ch); // 加入到数字缓存中
} else { // 非数字的情况
String tempStr = temp.toString(); // 将数字缓存转为字符串
if (!tempStr.isEmpty()) {
//long num = Long.parseLong(tempStr); // 将数字字符串转为长整型数
numberStack.push(tempStr); // 将数字压栈
temp = new StringBuffer(); // 重置数字缓存
}
// 判断运算符的优先级,若当前优先级低于栈顶的优先级,则先把计算前面计算出来
//comparePri(ch)比较优先级:如果当前运算符比栈顶元素运算符优先级高则返回true,否则返回false
while (!comparePri(ch) && !symbolStack.empty()) {
String a = numberStack.pop(); // 出栈,取出数字,后进先出
String b = numberStack.pop();
- 注意在算数时符号是有优先级的
// 符号优先级说明(从高到低):
// 第1级: (
// 第2级: * ÷
// 第3级: + -
// 第4级: )
char top = symbolStack.peek(); // 查看堆栈顶部的对象,注意不是出栈
if (top == '(') {
return true;
}
// 比较优先级
switch (symbol) {
case '(': // 优先级最高
return true;
case '*': {
if (top == '+' || top == '-') // 优先级比+和-高
return true;
else
return false;
}
case '÷': {
if (top == '+' || top == '-') // 优先级比+和-高
return true;
else
return false;
}
case '+':
return false;
case '-':
return false;
case ')': // 优先级最低
return false;
case '=': // 结束符
return false;
default:
break;
}
return true;
}
- 检查算术表达式的基本合法性,符合返回true,否则false
private boolean isStandard(String numStr) {
if (numStr == null || numStr.isEmpty()) // 表达式不能为空
return false;
Stack<Character> stack = new Stack<Character>(); // 用来保存括号,检查左右括号是否匹配
boolean b = false; // 用来标记'='符号是否存在多个
for (int i = 0; i < numStr.length(); i++) {
char n = numStr.charAt(i);
// 判断字符是否合法
if (!(isNumber(n) || "(".equals(n + "") || ")".equals(n + "")
|| "+".equals(n + "") || "-".equals(n + "")
|| "*".equals(n + "") || "÷".equals(n + "") || "/".equals(n + "")
|| "=".equals(n + ""))) {
return false;
}
// 将左括号压栈,用来给后面的右括号进行匹配
if ("(".equals(n + "")) {
stack.push(n);
}
if (")".equals(n + "")) { // 匹配括号
if (stack.isEmpty() || !"(".equals((char) stack.pop() + "")) // 括号是否匹配
return false;
}
// 检查是否有多个'='号
if ("=".equals(n + "")) {
if (b)
return false;
b = true;
}
}
// 可能会有缺少右括号的情况
if (!stack.isEmpty())
return false;
// 检查'='号是否不在末尾
if (!("=".equals(numStr.charAt(numStr.length() - 1) + "")))
return false;
return true;
}
LinkedHashMap<Integer, String> rightAnswerMap = new LinkedHashMap<Integer, String>();
LinkedHashMap<Integer, String> exerciseMap = new LinkedHashMap<Integer, String>();
ArrayList<Integer> rightRecord = new ArrayList<Integer>();
ArrayList<Integer> wrongRecord = new ArrayList<Integer>();
CreateExercise ce = new CreateExercise();
SavaTotxt save = new SavaTotxt();
ce.setMax_num(max_num);
for (int i = 1; i <= problems_num; i++) {
String problem = ce.create();
exerciseMap.put(i, problem);
// int i=1;String problem="(2/5-9)/10÷8";
String ns = problem;// 必要时,修改随机生成的题目的符号方便计算;problem是原始随机生的题目,这是要显示的
int rightbrackets;// 题目中右括号位置
int leftbrackets;// 题目中左括号位置
if (problem.contains(")")) {
// 因为题目把a/b当成一个数会压入栈,这两个if语句解决随机生成的题目出现(a+b)/c,
// 会先计算a+b=v,然后把v压入栈,再继续执行程序的时候会把/c当成一个数压入栈,再往后计算会出问题
rightbrackets = problem.indexOf(")");
leftbrackets = problem.indexOf("(");
if (rightbrackets != problem.length() - 1 && problem.charAt(rightbrackets + 1) == '/') {
StringBuilder sb = new StringBuilder(problem);
if (leftbrackets - 1 > 0 && problem.charAt(leftbrackets - 1) == '÷')// 这个解决括号前面是÷号要变号
sb.replace(rightbrackets + 1, rightbrackets + 2, "*");
else
sb.replace(rightbrackets + 1, rightbrackets + 2, "÷");
ns = sb.toString();
5.测试运行
这次项目使用的仅仅是数值上的运算,运算符与数字都随机生成,出错的概率在现如今计算机的体系结构以及算力的基础上应该是非常小的。
我们对题目设计了一个是否做答的选项,可供使用者进行选择,如果使用者选择y(yes)则立即作答,得到的答题结果会存在Grade_date文件里面,并且明确了哪题是正确的,哪题是错误的;选择n(no)则只产生题目,这些题目可以保存下来,当然答案也会一并保存,这样的话就可以由使用者在线下打印出来做题,然后依照答案进行批改。