zoukankan      html  css  js  c++  java
  • 结对项目(JAVA)

    项目成员: 邓镇港 3117004608 陈嘉欣 3117004604 ## 一、Github项目地址: **[https://github.com/kestrelcjx/operation_expression](https://github.com/kestrelcjx/operation_expression)** ## 二、PSP表格 PSP2.1|Personal Software Process Stages|预估耗时(分钟)|实际耗时(分钟) -|-|-|- Planning|计划|30|25 Estimate|估计这个任务需要多少时间|10|12 Development|开发|600|488 Analysis|需求分析|120|150 Design Spec|生成设计文档|30|55 Design Review|设计复审|40|50 Coding Standard|代码规范|20|65 Design|具体设计|60|40 Coding|具体编码|480|460 Code Review|代码复审|30|25 Test|测试(自我测试,修改代码,提交修改)|60|125 Reporting|报告|60|100 Test Report|测试报告|20|35 Size Measurement|计算工作量|10|12 Postmortem & Process Improvement Plan|事后总结, 并提出过程改进计划|120|100 合计||1690|1742 ## 三、效能分析 把数字封装成类,每个数字类由整数、分子、分母三部分组成。在类中重新定义加减乘除方法,每个运算方法都会用到通分,约分,将他们写成reduction()方法,gcd()方法。 查重功能实现得比较简单,生成10000条题目所需的时间很短: ![](https://img2018.cnblogs.com/blog/1797681/201910/1797681-20191016221750697-932861992.png) ![](https://img2018.cnblogs.com/blog/1797681/201910/1797681-20191016221800553-856069180.png)

    代码覆盖率:

    四、设计实现过程

    这次的项目需求是自动生成四则运算题目,难点在于随机数的处理和优先级的计算。在阅读完题目并分析需求后,我们先解决的是随机数的生成。因为要求有自然数和真分数,我们用到了一个数字类BasicWork来产生随机数。数字类定义一个数为带分数,分子为零的时候生成一个整数,否则生成一个真分数。这样做的好处是可以将自然数和真分数都统一,在后续的生成和计算过程能够通过调用数字类的方法处理。在数字类中,因为每个随机数都有3个部分组成,我们重新定义了数字类的加减乘除方法。数字类中还包括一个约分方法reduction()对生成的随机数和计算的结果进行处理,确保数字类满足是自然数或真分数的需求。

    CreatExpress类用来随机生成式子,用一个随机数来决定式子的操作数个数,根据操作数个数随机生成运算符并连接成四则运算表达式。生成括号这一部分的处理,是通过判断括号出现的正确位置来随机生成。

    MainShow主类则是显示出相关的使用信息,接收用户传入的参数。实现生成题目文件和答案文件需求的方法写在主类中,循环生成式子的同时把式子逐条写进题目文件里,并计算出答案写进答案文件。判断表达式重复的过程就是判断计算过程是否重复,这里仅仅是判断结果是否相同,不够完善。生成式子时调用主类的check()方法计算得出答案,并判断答案是否一致进行正确统计。

    五、代码说明

    对表达式字符串逐个字符判断,将操作数与操作符分隔,同时,将原来的中缀表达式转换为后缀表达式进行计算。
    对于将中缀表达式转后缀表达式,进行如下操作:从表达式左到右进行操作,如果是数值,将其放入number数组模拟的栈;如果是操作符,判断symbol数组模拟的栈,如果栈为空或栈顶为左括号,操作符直接进栈,如果栈顶为操作符,根据操作符优先级判断,如果栈顶操作符优先级低,操作符直接进栈,否则,将栈顶操作符放入number数组,继续讨论栈顶元素;如果是左括号,直接进栈;如果是右括号,将栈顶操作符放入number数组,直到栈顶为左括号,括号不放入number数组。最后将symbo模拟的栈中剩余操作符取出放入number数组。
    于是,我们便得到后缀表达式,对后缀表达式进行计算,从表达式(number数组)左到右进行操作,如果是操作数,放入stk栈;如果是操作符,将stk栈顶2个元素进行计算,再将结果放入stk栈。最后,stk栈剩余一个操作数,便是表达式结果,运算无误则方法返回结果。在计算过程中,判断是否出现负数,如果出现负数方法返回null值,表示表达式不合法。

    	//判断表达式是否合法,是否重复
    	public static BasicWork check(String s) {
    		boolean flag = true;
    		String symbol[] = new String[100];
    		int sym = 0;
    		String number[] = new String[100];
    		int num = 0;
    		String str = "";
    		//计算、判断合法、判断重复
    		for(int i = 0; i < s.length(); i++) {
    			if(s.charAt(i) == '+' || s.charAt(i) == '-' || s.charAt(i) == '×' || s.charAt(i) == '÷'
    					|| s.charAt(i) == '(' || s.charAt(i) == ')') {
    				if(!str.equals("")) {
    					number[num++] = str;
    					str = "";
    				}
    				if(s.charAt(i) == '+') {
    					while(sym != 0 && !symbol[sym-1].equals("(")) {
    						number[num++] = symbol[sym-1];
    						sym--;
    					}
    					symbol[sym++] = "+";
    				}
    				else if(s.charAt(i) == '-') {
    					while(sym != 0 && !symbol[sym-1].equals("(")) {
    						number[num++] = symbol[sym-1];
    						sym--;
    					}
    					symbol[sym++] = "-";
    				}
    				else if(s.charAt(i) == '×') {
    					while(sym != 0 && (symbol[sym-1].equals("×") || symbol[sym-1].equals("÷"))) {
    						number[num++] = symbol[sym-1];
    						sym--;
    					}
    					symbol[sym++] = "×";
    				}
    				else if(s.charAt(i) == '÷') {
    					while(sym != 0 && (symbol[sym-1].equals("×") || symbol[sym-1].equals("÷"))) {
    						number[num++] = symbol[sym-1];
    						sym--;
    					}
    					symbol[sym++] = "÷";
    				}
    				else if(s.charAt(i) == '(') {
    					symbol[sym++] = "(";
    				}
    				else if(s.charAt(i) == ')') {
    					while(sym != 0 && !symbol[sym-1].equals("(")) {
    						number[num++] = symbol[sym-1];
    						sym--;
    					}
    					if(sym != 0 && symbol[sym-1].equals("(")) sym--;
    				}
    			}
    			else {
    				str += s.charAt(i);
    			}
    		}
    		BasicWork tempA, tempB;
    		if(!str.equals("")) number[num++] = str;
    		while(sym > 0) {
    			number[num++] = symbol[sym-1];
    			sym--;
    		}
    //		for(int i = 0; i < num; i++) System.out.print(number[i]+" ");
    //		System.out.println();
    		Stack<BasicWork> stk = new Stack<BasicWork>();
    		for(int i = 0; i < num; i++) {
    			if(number[i].equals("+")) {
    				tempA = stk.peek();
    				stk.pop();
    				tempB = stk.peek();
    				stk.pop();
    				tempA = tempB.add(tempA);
    				stk.push(tempA);
    				
    			}
    			else if(number[i].equals("-")) {
    				tempA = stk.peek();
    				stk.pop();
    				tempB = stk.peek();
    				stk.pop();
    				tempA = tempB.sub(tempA);
    				stk.push(tempA);
    				if(tempA.zheng < 0 || tempA.fenzi < 0||tempA.fenmu<0) {
    					flag = false;
    					break;
    				}
    			}
    			else if(number[i].equals("×")) {
    				tempA = stk.peek();
    				stk.pop();
    				tempB = stk.peek();
    				stk.pop();
    				tempA = tempB.mul(tempA);
    				stk.push(tempA);
    			}
    			else if(number[i].equals("÷")) {
    				tempA = stk.peek();
    				stk.pop();
    				tempB = stk.peek();
    				stk.pop();
    				if(tempA.zheng == 0 && tempA.fenzi == 0) {
    					flag = false;
    					break;
    				}
    				tempA = tempB.div(tempA);
    				stk.push(tempA);
    			}
    			else {
    				stk.push(BasicWork.toBasicWork(number[i]));
    			}
    		}
    		if(flag == false) return null;
    		else return stk.peek();
    	}
    

    随机生成一条式子

    	//生成一条式子
    	public static String express(int limit,int opnum) {
    		String str = null;
    		for(int i=0;i<opnum;i++) {
    			a[i]=new BasicWork(limit);
    			BasicWork.reduction(a[i]);
    			
    		}
    		if(opnum == 2) {
    			str = a[0].toString() + getSymbol() + a[1].toString();
    		}
    		else if(opnum == 3) {
    			int randx = (int)(Math.random()*10);
    			if(randx == 0) 
    				str = "("+a[0].toString() + getSymbol() + a[1].toString() + ")" + getSymbol() + a[2].toString();
    			else if(randx == 1)
    				str = a[0].toString() + getSymbol() + "(" + a[1].toString() + getSymbol() + a[2].toString() + ")";
    			else 
    				str = a[0].toString() + getSymbol() + a[1].toString() + getSymbol() + a[2].toString();
    			
    		}
    		else {
    			int randx = (int)(Math.random()*30);
    			if(randx == 0)
    				str = "(" + a[0].toString() + getSymbol() + a[1].toString() + getSymbol() + a[2].toString() + ")" 
    				+ getSymbol() + a[3].toString();
    			else if(randx == 1)
    				str = a[0].toString() + getSymbol() + "(" + a[1].toString() + getSymbol() + a[2].toString() + ")"
    				+ getSymbol() + a[3].toString();
    			else if(randx == 2)
    				str = "(" + a[0].toString() + getSymbol() + "(" + a[1].toString() + getSymbol() + a[2].toString() + "))"
    				+ getSymbol() + a[3].toString();
    			else if(randx == 3)
    				str = a[0].toString() + getSymbol() + "(" + a[1].toString() + getSymbol() + "(" + a[2].toString()
    				+ getSymbol() + a[3].toString() + "))";
    			else if(randx == 4)
    				str = "(" + a[0].toString() + getSymbol() + a[1].toString() + ")" + getSymbol() + "(" + a[2].toString()
    				+ getSymbol() + a[3].toString() + ")";
    			else 
    				str = a[0].toString() + getSymbol() + a[1].toString() + getSymbol() + a[2].toString()
    					+ getSymbol() + a[3].toString();
    		}
    		return str;
    		
    	}
    

    数字类BasicWork

    public class BasicWork {
    	
    	int fenzi;
    	int fenmu;
    	int zheng;
    	
    	public BasicWork() {
    		
    	}
    	
    	public BasicWork(int limit) {
    //		fenzi=(int)(0+Math.random()*(limit-0+1));
    //		zheng=(int)(0+Math.random()*(limit-0+1));
    		zheng=0;
    		fenmu=(int)(1+Math.random()*(limit-1+1));
    		fenzi=(int)(Math.random()*fenmu*limit);
    		reduction(this);
    	}
    	
    	//用于测试
    	public BasicWork(int a,int b,int c) {
    		fenzi=a;
    		fenmu=b;
    		zheng=c;
    	}
    	
    	//约分方法
    	public static void reduction(BasicWork reop) {
    		int re=gcd(reop.fenzi,reop.fenmu);
    		re = re == 0 ? 1 : re;
    	    reop.fenzi=reop.fenzi/re;
    	    reop.fenmu=reop.fenmu/re;
    	    //System.out.println(reop.fenzi + " " + reop.fenmu);
    	    try {
    			if(reop.fenzi>=reop.fenmu) {
    				reop.zheng=reop.zheng+reop.fenzi/reop.fenmu;
    				reop.fenzi=reop.fenzi%reop.fenmu;
    				if(reop.fenzi==0) reop.fenmu=1;
    			}
    		} catch (Exception e) {
    			e.printStackTrace();
    		}
    	}
    	
    
    	
    	public BasicWork add(BasicWork a) {
    		BasicWork temp=new BasicWork();
    		temp.zheng=zheng+a.zheng;
    	    temp.fenmu=fenmu*a.fenmu;
    	    temp.fenzi=fenzi*a.fenmu+a.fenzi*fenmu;
    	    //约分
    	    reduction(temp);
    		return temp;
    	}
    	
    	public BasicWork sub(BasicWork s) {
    		BasicWork temp=new BasicWork();
    		temp.fenzi=fenzi+fenmu*zheng;
    		temp.zheng=0;
    		temp.fenmu=fenmu;
    		s.fenzi=s.fenzi+s.fenmu*s.zheng;
    		s.zheng=0;
    		temp.fenzi=temp.fenzi*s.fenmu;
    		s.fenzi=s.fenzi*temp.fenmu;
    		temp.fenmu=temp.fenmu*s.fenmu;
    		temp.fenzi=temp.fenzi-s.fenzi;
    		//约分
    		reduction(temp);
    		return temp;
    	}
    	
    	public BasicWork mul(BasicWork m) {
    		BasicWork temp=new BasicWork();
    		temp.fenzi=fenzi+fenmu*zheng;
    		temp.zheng=0;
    		temp.fenmu=fenmu;
    		m.fenzi=m.fenzi+m.fenmu*m.zheng;
    		m.zheng=0;
    		temp.fenmu=temp.fenmu*m.fenmu;
    		temp.fenzi=temp.fenzi*m.fenzi;
    		//约分
    		reduction(temp);
    		return temp;
    	}
    	
    	public BasicWork div(BasicWork d) {
    		d.fenzi+=d.fenmu*d.zheng;
    		d.zheng=0;
    		int i;
    		i=d.fenmu;
    		d.fenmu=d.fenzi;
    		d.fenzi=i;
    		return this.mul(d);
    	}
    	
    	public boolean equals(BasicWork rhs) {
    		return (zheng*fenmu+fenzi)*rhs.fenmu == (rhs.zheng*rhs.fenmu+rhs.fenzi)*fenmu;
    	}
    	
    	private static int gcd(int a,int b) {
    		if(b==0) return a;
    		return gcd(b,a%b);
    	}
    	
    	public String toString() {
    		String s=new String();
    		if(fenzi==0) s=zheng+"";
    		else if(zheng==0) s=fenzi+"/"+fenmu;
    		else s=zheng+"'"+fenzi+"/"+fenmu;
    		return s;
    	}
    	
    	//命令行传入参数转换为整型
    	public static int toInt(String s) {
    		int ans=0;
    		for(int i=0;i<s.length();i++) {
    			ans=ans*10+s.charAt(i)-'0';
    		}
    		return ans;
    	}
    	
    	public static BasicWork toBasicWork(String str) {
    		BasicWork temp = new BasicWork();
    		ArrayList<Integer> ary = new ArrayList<Integer>();
    		int tmp = 0;
    		for(int i = 0; i < str.length(); i++) {
    			if(str.charAt(i) >= '0' && str.charAt(i) <= '9') tmp = tmp*10+str.charAt(i)-'0';
    			else {
    				ary.add(tmp);
    				tmp = 0;
    			}
    		}
    		ary.add(tmp);
    		if(ary.size() == 1) {
    			temp.zheng = ary.get(0);
    			temp.fenzi = 0;
    			temp.fenmu = 1;
    		}
    		else if(ary.size() == 2) {
    			temp.zheng = 0;
    			temp.fenzi = ary.get(0);
    			temp.fenmu = ary.get(1);
    		}
    		else {
    			temp.zheng = ary.get(0);
    			temp.fenzi = ary.get(1);
    			temp.fenmu = ary.get(2);
    		}
    		return temp;
    	}
    }
    

    六、测试运行

    测试-n -r



    测试-e -a
    这里选用刚刚生成的题目文件和答案文件,答案文件修改几个答案以验证功能




    生成10000条题目

    经验证,功能正确实现。

    七、项目小结

    1. 这次的核心是数字类和转换为后缀表达式去计算答案。数字类将操作数封装成类,在后续的操作中会简单很多,而且代码更简洁易懂。
    2. 初次使用结对编程这种软件开发的方法开发项目,受益匪浅,2个人若是能很好磨合,将达到事半功倍的效果。打代码过程互相鼓励,互相监督,比起自己一个人打代码更有激情。
  • 相关阅读:
    python基础(9):基本数据类型四(set集合)、基础数据类型补充、深浅拷贝
    python基础(8):基本数据类型三(dict)、is和==、编码和解码
    python基础(7):基本数据类型二(list、tuple)、range
    python基础(1):python介绍、python发展史
    python基础(6):基本数据类型一(int、bool、str)
    python基础(5):格式化输出、基本运算符、编码问题
    python基础(4):用户交互、if判断、while循环、break和continue
    python基础(2):python的安装、第一个python程序
    python基础(3):变量、常量、注释、基本数据类型
    java基础(32):类加载、反射
  • 原文地址:https://www.cnblogs.com/Kestrel/p/11689579.html
Copyright © 2011-2022 走看看