这个作业属于哪个课程 | 计科二班 |
---|---|
这个作业要求在哪里 | 结对项目 |
这个作业的目标 | 熟悉结对编程 |
项目成员
龙新超 3121004921 github链接:龙新超github
艾孜海尔江 3121004900 github链接:海尔江github
PSP表格
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 15 | 15 |
· Estimate | · 估计这个任务需要多少时间 | 15 | 15 |
Development | 开发 | 715 | 695 |
· Analysis | · 需求分析 (包括学习新技术) | 150 | 150 |
· Design Spec | · 生成设计文档 | 15 | 15 |
· Design Spec | · 设计复审 | 20 | 20 |
· Coding Standard | · 代码规范 (为目前的开发制定合适的规范) | 20 | 40 |
· Design | · 具体设计 | 60 | 40 |
· Coding | · 具体编码 | 240 | 250 |
· Code Review | · 代码复审 | 120 | 90 |
· Test | · 测试(自我测试,修改代码,提交修改) | 90 | 90 |
Reporting | 报告 | 60 | 50 |
· Test Repor | · 测试报告 | 20 | 20 |
· Size Measurement | · 计算工作量 | 20 | 15 |
· Postmortem & Process Improvement Plan | · 事后总结, 并提出过程改进计划 | 20 | 15 |
· 合计 | 790 | 760 |
设计实现
项目结构
实体类:分数整数Fraction类,表达式OperationExpression
工具类:DuplicateCheck
服务类:CaculateService,CheckService,getEpression
入口:OperationPro
设计思路
考虑到分数的实现,所以应将整数与分数作为一个对象来处理,即整数就是分母为1的分数。也因此做了实体类Fraction
受到Fraction启发,做了实体类OperationExpression,它的属性包含了表达式及其答案
题目生成设计思路:
于是就可以用一个OperationExpression对象e,运用getExpression的getExp方法生成一个为e的表达式,getExp()方法中调用了CalculateService的calculate()计算方法得到答案。calculate()方法中产生了负数则会返回空值,可根据这个空值判断表达式是否存在负数,若存在则丢弃重新生成。还要进行DuplicateCheck类的查重。通过上述步骤,即可生成一道题目。
关键代码
- getExpression
public class getExpression {
private static Random r = new Random();
static List l = new ArrayList();
//获得字符串集合,并生成表达式
public List getExp(OperationExpression e,int limit){
Fraction f1 = new Fraction(r.nextBoolean(),limit);
List stringList = new ArrayList();
List l = new ArrayList();
l.add(f1);
stringList.add(f1.toString());
int a = r.nextInt(3); // [0,3),取值为0/1/2,随机生成运算符个数
do{
express(e,l,stringList,limit);
a--;
}while (a>=0);
Fraction f =CalculateService.calculate(l);
if(f==null){
return null;
}
e.setRes(f);
e.setStringList(stringList);
return stringList;
}
static void express(OperationExpression e,List l,List stringList,int limit){
Fraction f = new Fraction(r.nextBoolean(),limit);
//out.println(f.toString()+"f..");
int a = r.nextInt(4); //取值范围:[0,4)中的0/1/2/3,随机取运算符
switch (a){ //0:加,1:减,2:乘,3:除
case 0: l.add("+");l.add(f);
stringList.add("+");stringList.add(f.toString());
break;
case 1:
//检查是否存在e1-e2<0的情况,存在则应调换位置
// out.println(l+"测试");
// out.println(stringList+"测试");
l.add("-");l.add(f);
stringList.add("-");stringList.add(f.toString());
break;
case 2: l.add("×");l.add(f);
stringList.add("×");stringList.add(f.toString());
break;
case 3: l.add("÷");l.add(f);
stringList.add("÷");stringList.add(f.toString());
break;
default:
out.println("出错");
}
e.setList(l);
}
}
2.CaculateService
public class CalculateService {
/**
* 中序变为后序
* @param list
* @return
*/
public static Stack toPostFix(List list){
Stack num = new Stack();
Stack<String> action = new Stack<>();
int symble = 0;
for (Object o : list) {
symble = flag(o, num, action);
switch (symble) {
case 1://数字直接入栈
num.push(o);
break;
case 2://操作符栈为空直接入栈
action.push((String) o);
break;
case 3://当前操作符比栈顶操作符优先级高入栈
action.push((String) o);
break;
case 4:
//弹出所有比当前操作符优先级高的,直到遇到左括号或者为空
while (!action.empty() && action.peek()!="(" && !prior((String)o,action.peek())){
num.push(action.pop());//action弹栈并压入number
}
action.push((String) o);//操作符压栈
break;
case 5://左括号无条件入操作栈
action.push((String) o);
break;
case 6:
first: while (!action.isEmpty()) {//action弹栈并压入number栈直到遇到左括号
String temp = action.pop();
if (temp.equals("(")) {
break first;
} else {
num.push(temp);
}
}
break;
default:
break;
}
}
Stack temp = new Stack();
//将剩下的操作符压入number栈中
for (String s : action) {
num.push(s);
}
//反序
for (Object o : num) {
temp.push(o);
}
return temp;
}
/**
* 中序转后序表达式的各种逻辑判断,将判断的结果送入toPostfix()进行各种情况的具体逻辑处理
*
* @param o
* @param number number栈
* @param action action栈
* @return 返回各种情况的symbol
*/
public static int flag(Object o, Stack number, Stack<String> action) {
if (o instanceof Fraction)
return 1;// number
//是操作符
String s = (String)o;
if (s.matches("(\\+)|(\\-)|(\\×)|(\\÷)")) {
if (action.isEmpty()) {
return 2;// action为空
} else if (prior(s, action.peek())) {
return 3;// action不为空,操作符优先级高于栈顶操作符
} else {
return 4;// action不为空,操作符优先级不高于栈顶操作符
}
}
if (s.matches("\\("))
return 5;// 左括号
if (s.matches("\\)"))
return 6;// 右括号
//都不是
return 0;
}
/**
* 判断操作符和栈顶操作符的优先级
* @param s1 操作符
* @param s2 栈顶操作符
* @return 优先级
*/
public static Boolean prior(String s1, String s2) {
if (s2.matches("\\("))
return true;
if (s1.matches("(\\×)|(\\÷)") && s2.matches("(\\+)|(\\-)"))
return true;
return false;
}
public static Fraction calculate(List list){
Stack stack = toPostFix(list);
Stack<Fraction> newStack = new Stack();
for (Object o : stack) {
if(o instanceof Fraction){
newStack.push((Fraction) o);
}else {
if(newStack.size()<2){
break;
}
Fraction a = newStack.pop();
Fraction b = newStack.pop();
switch ((String) o) {
case "+":
newStack.push(b.add(a));
break;
case "-":
Fraction fraction = b.sub(a);
if(fraction.getNominator()<=0||fraction.getDenominator()<=0){
return null;
}
newStack.push(fraction);
break;
case "×":
newStack.push(b.muti(a));
break;
case "÷":
newStack.push(b.div(a));
break;
default:
break;
}
}
}
return newStack.pop();
}
}
3.DuplicateService
public class DuplicateCheck {
//l为判断的表达式集合,allList是已经存在的所有表达式集合
public boolean DuCheck(List l, List allList){
Iterator it = allList.iterator();
while (it.hasNext()){
List L = (List) it.next();
if(CheckList(l,L)) return true;
}
return false;
}
/*
*判断两个String类型的List是否完全相同
*大小一样,所有元素互相含有,元素顺序可以不一致
*/
//l1是l的形参,l2是allList中某个元素的形参
boolean CheckList(List l1,List l2){
if (l1 == l2) {
return true;
}
if (l1 == null && l2 == null)
{
return true;
}
if (l1 == null || l2 == null)
{
return false;
}
if (l1.size() != l2.size())
{
return false;
}
if (l1.containsAll(l2) && l2.containsAll(l1))
{
return true;
}
return false;
}
}
性能分析
内存占用情况
总体性能
测试
测试代码
public class test {
@Test
public void test1(){
OperationPro.mainGenerate(10,10000);
}
@Test
public void test2(){
OperationPro.mainCheck("D:\\gitcode\\acofGDUT\\3121004921\\homework2\\Answer1.txt","D:\\gitcode\\acofGDUT\\3121004921\\homework2\\Answer.txt");
}
@Test
public void test3(){
getExpression getExpression = new getExpression();
List exp = getExpression.getExp(new OperationExpression(null, null, null), 10);
System.out.println(exp);
}
@Test
public void test4(){
getExpression getExpression = new getExpression();
List exp = getExpression.getExp(new OperationExpression(null, null, null), 3);
System.out.println(exp);
}
@Test
public void test5(){
Fraction a = new Fraction(true,6);
Fraction b = new Fraction(true,6);
System.out.println(a.sub(b));
}
@Test
public void test6(){
Fraction a = new Fraction(false,10);
Fraction b = new Fraction(true,8);
System.out.println(a.div(b));
}
@Test
public void test7(){
Fraction a = new Fraction(false,8);
Fraction b = new Fraction(false,8);
System.out.println(a.add(b));
}
@Test
public void test8(){
Fraction a = new Fraction(false,8);
Fraction b = new Fraction(false,8);
System.out.println(a.sub(b));
}
@Test
public void test9(){
System.out.println(CalculateService.prior("+", "-"));
}
@Test
public void test10(){
getExpression getExpression = new getExpression();
List exp = getExpression.getExp(new OperationExpression(null, null, null), 3);
System.out.println(CalculateService.toPostFix(exp));
}
测试运行结果
覆盖率
文档生成情况
复制一份答案Answer1.txt 修改一部分答案,检查Grade文档
项目小结
龙新超:一起编写代码,我们能够迅速发现和纠正彼此的错误。这种实时反馈有助于提高代码质量,而且我学到了很多新知识,因为合作伙伴带来了不同的观点和经验。此外,我们在讨论设计和实现方案时能够做到更全面的思考,这也有助于我们制定更好的解决方案。
海尔江:两个人一起工作,能够共同解决问题,一起思考最佳实践,并发现彼此的盲点。这种协作方式加速了问题的诊断和解决,两个人互相交流和学习的经验也非常有价值。尽管在一开始可能感到有些不习惯,但我认为结对编程是一种提高代码质量和工作效率的重要实践。