课程 | 软件工程 |
---|---|
要求 | 结对项目作业 |
题目 | 四则运算生成器 |
成员 | 学号 |
---|---|
陈树东 | 3119005407 |
冯波昌 | 3119005410 |
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 30 | 40 |
Estimate | 估计这个任务需要多少时间 | 2000 | 2560 |
Development | 开发 | 1200 | 1350 |
Analysis | 需求分析 (包括学习新技术) | 60 | 130 |
Design Spec | 生成设计文档 | 20 | 30 |
Design Review | 设计复审 (和同事审核设计文档) | 30 | 15 |
Coding Standard | 代码规范 (为目前的开发制定合适的规范) | 30 | 10 |
Design | 具体设计 | 30 | 30 |
Coding | 具体编码 | 30 | 60 |
Code Review | 代码复审 | 15 | 30 |
Test | 测试(自我测试,修改代码,提交修改) | 500 | 780 |
Reporting | 报告 | 30 | 60 |
Test Report | 测试报告 | 30 | 15 |
Size Measurement | 计算工作量 | 15 | 15 |
Postmortem & Process Improvement Plan | 事后总结, 并提出过程改进计划 | 30 | 60 |
合计 | 5050 | 5185 |
1.对自然数以及真分数进行四则运算
2.用 -n 参数控制生成题目个数 -r 参数控制题目中数值范围
3.运算过程不能产生负数
4.生成的题目中如果存在形如e1÷ e2的子表达式结果是真分数
5.不超过三个运算符
6.程序一次运行过程中,题目不能重复
7.在生成题目的同时,计算出所有题目的答案,并存入执行程序的当前目录下的Answers.txt文件
8.程序应能支持一万道题目的生成。
9.程序支持对给定的题目文件和答案文件,判定答案中的对错并进行数量统计
检查 CheckGrade:
while((an=BRanswer.readLine())!=null) { ex=BRexersise.readLine(); int point=an.indexOf(".");//找到"."所在处,因为答题格式和答案格式均为No.Answer,只需要比较“."后的答案即可 String stran=an.substring(point+1);//取答案 stran=stran.trim(); String strex=ex.substring(point+1);//取标准答案 strex=strex.trim(); if(stran.equals(strex)) { //答案和标准答案相同时,将题号压入Correct栈 String wno=an.substring(0, point); Wrong.add(wno); }else { //答案和标准答案不同时,将题号压入Wrong栈 String cno=an.substring(0, point); Correct.add(cno); } }
中缀表达式转换成后缀表达式:
/** *将中缀表达式转换为后缀表达式入栈 * @param infix * retrun postfix */ public static List<String> TransferToPostfix(List<String> infix){ List<String> postfix=new ArrayList<>(); Stack<String> s1= new Stack<>(); for (String str : infix) { if(str.equals("(")) { s1.push(str); }//若是左括号,进栈 else if(str.equals(")")) { while(!s1.peek().equals("(")) { postfix.add(s1.pop()); }//若是右括号,将栈内内容出栈直到遇到左括号为止 s1.pop(); } else if(str.equals("+")||str.equals("-")||str.equals("×")||str.equals("÷")) {//遇到运算符时 while (s1.size() != 0 && getValue(s1.peek()) >= getValue(str)) { postfix.add(s1.pop()); }//栈非空,从栈中弹出元素直到遇到更低级的运算符/栈空,再入栈 s1.push(str); } else { postfix.add(str); }//栈空,直接入栈 } while (s1.size() != 0) { postfix.add(s1.pop()); }//将栈内所有元素弹出 return postfix; }
查重表达式:
/** *查重表达式的生成 */ public List<String> getCheck(String str) { List<String> linfix = transform.ToList(str); List<String> lpostfix = calculates.TransferToPostfix(linfix); List<String> cnkiexp = new ArrayList<String>(); Stack<String> st = new Stack<String>(); String top1 ; top1= ""; String top2 ; top2= ""; for (String kk : lpostfix) { if (!calculates.IsOperator(kk)) {//不是运算符时 st.push(kk);//压入栈 } else if (kk.equals("+") || kk.equals("-") || kk.equals("×")) {//是运算符 cnkiexp.add(kk); top1 = st.pop(); top2 = st.pop(); if (top2 != "¥") { cnkiexp.add(top2); } if (top1 != "¥") { cnkiexp.add(top1); } st.push("¥"); } else if (kk.equals("÷")) { cnkiexp.add(kk); top1 = st.pop(); top2 = st.pop(); cnkiexp.add(top2); cnkiexp.add(top1); st.push("¥"); } } return cnkiexp; }
一开始没有什么思路,在请教了同学之后,他们提供了几个思路给我:
①将四则运算表达式存储在二叉树中,中序遍历还原成四则运算表达式
②利用栈,转换成后缀表达式 如:a + b*c + (d * e + f) * g → a b c * + d e * f + g * +
在了解到 JAVA本身有stack类再加上我们递归以及二叉树学的不好,果断选择了用线性表来实现。
具体的过程如下:
1)遇到操作数,直接输出。
2)遇到操作符,将其放入到栈中,遇到左括号也将其放入栈中。
3)直到遇到一个右括号,将栈元素弹出,将弹出的操作符输出直到遇到左括号为止。注意,左括号只弹出并不输出。
4)遇到任何其他的操作符,如加减乘除运算符等,从栈中弹出元素直到遇到发现更低优先级的元素(或者栈为空)为止。弹出完这些元素后,才将遇到的操作符压入到栈中。
注意:只有在遇到" ) "的情况下才弹出" ( ",其他情况都不会弹出" ( "。
5)如果我们读到了输入的末尾,则将栈中所有元素依次弹出。
只有加法乘法有交换律,所以只需要对这两个进行特别判断
后缀表达式存进进线性表1中
线性表1作为key值存入哈希表
将“+”,“ * ”号两边的运算数交换存入线性表2
判断两线性表是否相同即可;
10000道小于10的运算:
10道小于10的运算:
陈树东:
1.这次项目是结对项目,需要两个队友相互间的配合,也让我们学会了如何合作完成项目
2.一开始我们完全没有头绪,我们先考虑需要有多少个需求,然后考虑用什么方法,最后才开始动手写程序
3这次对于我们两个都是一个不小的挑战,经过这次项目,我们更加了解到团队项目的流程与分工
冯波昌:
1.结对项目不再是单枪匹马莽着来了,两个人前期的沟通很重要。
2.双方罗列出各自的思路,再一起讨论确定最终的方向,比一个人想方法,简单高效很多。
3.两个人对题目的理解能互相激励对方的思路,不同功能的实现有不同的方法,这里需要大家一起确定方向。
4.在碰到解决不来的问题时,及时的请教同学,能更好的找到正确的思路。