结对项目(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条题目
经验证,功能正确实现。
七、项目小结
- 这次的核心是数字类和转换为后缀表达式去计算答案。数字类将操作数封装成类,在后续的操作中会简单很多,而且代码更简洁易懂。
- 初次使用结对编程这种软件开发的方法开发项目,受益匪浅,2个人若是能很好磨合,将达到事半功倍的效果。打代码过程互相鼓励,互相监督,比起自己一个人打代码更有激情。
结对项目(JAVA)的更多相关文章
- 结对项目(java实现)
一 .Github项目地址:https://github.com/734635746/MyApp 二.PSP表格 PSP2.1 Personal Software Process Stages 预估耗 ...
- 2018-2019-2 《Java程序设计》结对项目阶段总结《四则运算——整数》(二)
20175218 2018-2019-2 <Java程序设计>结对项目阶段总结<四则运算--整数> 一.需求分析 实现一个命令行程序,要求: 自动生成小学四则运算题目(加,减, ...
- # 2019-2020-4 《Java 程序设计》结对项目总结
2019-2020-4 <Java 程序设计>结对项目阶段总结---<四则运算--整数> 一.需求分析 实现一个命令行程序 要求: 自动生成小学四则运算题目(加,减,乘,除): ...
- 结对项目3-功能增强型带基本函数计算java计算器
-----------------------------------------------------实验报告------------------------------------------- ...
- 结对项目:四则运算题目生成器(Java)
目录 一.需求分析 二.开发计划 三.实现方案 3.1 项目结构 3.2 代码说明 3.2.1 出题功能代码 3.2.3 批卷功能代码 3.2.3 四则运算功能代码 四.效能分析 4.1 程序效能 4 ...
- 复利计算--结对项目<04-11-2016> 1.0.0 lastest 阶段性完工~
结对项目:Web复利计算 搭档博客地址:25江志彬 http://www.cnblogs.com/qazwsxedcrfv/ 个人摘要: (2016-04-09-12:00)补充:之前传送门没做好, ...
- 高级四则运算器—结对项目总结(193 &105)
高级四则运算器—结对项目总结 为了将感想与项目经验体会分割一下,特在此新开一篇博文. 界面设计 啥都不说,先上图震慑一下... 上面的三个界面是我们本次结对项目的主界面,恩,我也觉得挺漂亮的!你问我界 ...
- WordCount结对项目
合作者:201631062124,201631062423 代码地址:https://gitee.com/yryx/WordCount 作业地址:https://edu.cnblogs.com/cam ...
- [2017BUAA软工]结对项目:数独扩展
结对项目:数独扩展 1. Github项目地址 https://github.com/Slontia/Sudoku2 2. PSP估计表格 3. 关于Information Hiding, Inter ...
随机推荐
- 【电脑】分屏显示输入信号超出范围调整为XXXXXXX
选提示的那个范围就OK了. 注意:1.修改的是外界显示器,不是主显示器/笔记本. 2.修改外接显示器,不影响主显示器/笔记本
- 【oracle】ORA-12638 : 身份证明检索失败
sqlnet.ora 1.删了 2.#注释了 背后缘由:待写
- 关于对pei
我现在才开始整理这个不算晚吧...... 望轻喷 学习博客 我们需要四个程序 1.暴力 2.“正解” 3.数据生成器 4.检查程序 暴力: 就是暴力 eg: #include <cstdio&g ...
- select标签刷新后保持之前选择值
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <selec ...
- Spring security 知识笔记【入门】
一.生成spring boot项目文件 二.pom文件如下 <?xml version="1.0" encoding="UTF-8"?> <p ...
- NetCore 开发时中文编码转换出现异常
在C#编程的时候难免会遇到需要转换编码的场合. 在Framwork中可以用System.Text.Encoding解决,但是到了core会发现,虽然也有这个东西,但几个关键的中文编码(比如GB2312 ...
- K8S 如何实现将git代码下拉到指定的容器路径中
gitRepo 是 kubernetes Volume类型中的一种,gitRepo volume可以实现将git代码下拉到指定的容器路径中. 备注:实现此功能,Pod运行的节点都必需要安装git.换句 ...
- 移动端布局方案—vw+rem
前言 首先你要知道 vw 和 rem 是什么?怎么使用? ①:简单来说 vw 是视口单位,相当于把视口等分成了100,1vw = 1; ②:rem是相对单位,设置根元素 html 的 font-siz ...
- 笔记本CPU性能排行
截图如下: 1. 图1 2. 图2 3. 4. 5. 6. 7. 8. 谢谢浏览!
- pytest_demo_实战1
1.根目录配置 pytest.ini [pytest] addopts = -p no:warnings 2.更改运行手势,系统配置 file -> setting -> Tools -& ...