算术题目生成器
这个作业属于哪个课程 | https://edu.cnblogs.com/campus/gdgy/CSGrade22-34 |
---|---|
这个作业要求在哪里 | https://edu.cnblogs.com/campus/gdgy/CSGrade22-34/homework/13230 |
这个作业的目标 | 实现一个自动生成小学四则运算题目的命令行程序 |
项目成员
- 张嘉乐 3122004544
- 唐学鹏 3119005703
项目 Gitee 链接:https://gitee.com/zippo_1/team-system
一.PSP表格
PSP2.1 | Personal Software Process Stages | 预估耗时 (分钟) | 实际耗时 (分钟) |
---|---|---|---|
Planning | 计划 | 25 | 30 |
·Estimate | ·估计这个任务需要多少 时间 | 10 | 10 |
Development | 开发 | 220 | 240 |
·Analysis | ·需求分析(包括学习新技术) | 120 | 120 |
·Design Spec | ·生成设计文档 | 30 | 20 |
·Design Review | ·设计复审 | 40 | 20 |
·Coding Standard | ·代码规范(为目前的开发 制定合适的规范) | 10 | 5 |
·Design | ·具体设计 | 60 | 40 |
·Coding | ·具体编码 | 60 | 40 |
·Code Review | ·代码复审 | 50 | 40 |
·Test | ·测试(自我测试,修改 代码,提交修改) | 60 | 60 |
Reporting | 报告 | 60 | 60 |
·Test Repor | ·测试报告 | 30 | 30 |
·Size Measurement | ·计算工作量 | 10 | 20 |
·Postmortem & Process Improvement Plan | ·事后总结,并提出过程改 进计划 | 20 | 30 |
·合计 | 805 | 765 |
二.需求分析
- 通过命令行控制所需要生成的题目数量和生成的操作数的取值范围
- 随机生成不重复的题目并输出到文件
- 操作符和操作数的运算顺序完全相同则视为重复
- 计算题目并将答案输出到文件中
三.各模块设计
- ArgException 参数异常类
- CheckArg 检查参数
- CreateQuestion 创建题目
- CheckQuestion 检查题目是否重复
- DataNode 查重时所需要的数据结构
- CalculateOne 计算一道题目出现负数返回空
- CalcAll 计算所有题目
- Operator 计算类
- DataTofile 将数据输出到文件
关键算法为CheckQuestion
算法作用为检查题目是否重复
点击查看代码
//当题库为空证明肯定不重复,直接返回true
//若不为空则遍历题库,根据题目要求可知,如果运算符的运算顺序相同且操作数也相同则重复,否则不重复
//先按实际运算符的执行顺序排序,排序结果放在List<dataNode>,dataNode中储存执行的运算符,和前后操作符的位置
//构建生成List<dataNode>的方法
public static void GetList(List<DataNode> list1, char[] symbol){
char[] symbol1=symbol.clone();
DataNode dataNode;
for(int i = 0;!Character.isSpaceChar(symbol1[i]); i++){//先找出括号,因为括号优先级最高,找出后为了后面方便也要把它删除
if(symbol1[i]=='('){
dataNode=new DataNode(symbol1[i+1],i,i+1);
symbol1[i+1]=' ';
symbol1[i+2]=' ';//把括号检测出来后删除
symbol1[i]=' ';//删除括号中的运算符,避免重复检测
int t=i;
for(;!Character.isSpaceChar(symbol1[t+3]);t++){
symbol1[t]=symbol1[t+3];
symbol1[t+3]=' ';
}
list1.add(dataNode);
}
}
for(int i=0;!Character.isSpaceChar(symbol1[i]);i++){//找乘除
if(symbol1[i]=='*'||symbol1[i]=='/'){
dataNode=new DataNode(symbol1[i],i,i+1);
list1.add(dataNode);
}
}
for(int i=0;!Character.isSpaceChar(symbol1[i]);i++){
if(symbol1[i]=='+'||symbol1[i]=='-'){
dataNode=new DataNode(symbol1[i],i,i+1);
list1.add(dataNode);
}
}
}
//其中dataNode
public class DataNode {
char symbol;//记录运算符
int first;//记录左操作数的位置
int second;//记录右操作数的位置
public DataNode(char symbol, int first, int second) {
this.symbol = symbol;
this.first = first;
this.second = second;
}
}
//然后拿待测数据和题库数据逐个比较,如果list<dataNode>的长度及list<dataNode>中symbol运算符都一样才有可能重复
//然后分情况比较
//比较运算符类
public static boolean CompareNumber(String[] a,List<DataNode> list1,String[] b,List<DataNode> list2){//如果重复返回true
//1.比较第一个节点的的左右两边
//2.true则判断第一个节点和第二个节点是否衔接,false则不重复
//3.衔接则比较衔接端的另一端的操作数相同则比较下一个操作数
//4.不衔接则比较两边操作数
int first1,first2;//左操作数所在的位置
int second1,second2;//右操作数的位置
for(int i=0;i<list1.size();i++){
first1=list1.get(i).first;//找出两组数据的第一个运算符的左右操作数
second1=list1.get(i).second;
first2=list2.get(i).first;
second2=list2.get(i).second;
//第一个比较两边
if(i==0){
if(a[first1].equals(b[first2])&&a[second1].equals(b[second2])||a[first1].equals(b[second2])&&a[second1].equals(b[first2])){//
continue;
}else {//其他情况直接break,后返回false
break;
}
}
if(i==1){//第二个运算符,先判断是不是衔接的
if(list1.get(i).first!=list1.get(i-1).second&&list1.get(i).second!=list1.get(i-1).first){//如果不衔接
if(list2.get(i).first!=list2.get(i-1).second&&list2.get(i).second!=list2.get(i-1).first){//检测数据也不衔接
if(a[first1].equals(b[first2])&&a[second1].equals(b[second2])||a[first1].equals(b[second2])&&a[second1].equals(b[first2])){//且重复,返回true,不用看最后一个
return true;
}else{
break;
}
}else{
break;
}
}else {//衔接,看下一个操作数(非衔接端)
if(list2.get(i).first==list2.get(i-1).second||list2.get(i).second==list2.get(i-1).first){//检测数据也要衔接
//找出要比较的操作数
int toCompare1,toCompare2;
if(list1.get(i).first==list1.get(i-1).second){
toCompare1=list1.get(i).second;
}else {//进来这里肯定是衔接的,else直接赋值另一个
toCompare1=list1.get(i).first;
}
if(list2.get(i).first==list2.get(i-1).second){
toCompare2=list2.get(i).second;
}else {
toCompare2=list2.get(i).first;
}
if(a[toCompare1].equals(b[toCompare2])){//比较重复则继续,如果只有两个字符则返回true
if(list1.size()==2){
return true;
}else{
continue;
}
}else{
break;
}
}else{
break;
}
}
}
if(i==2){//第三个字符,前面解决的第二个运算符且不衔接的情况,其实是三个运算符的情况,所以执行这段的情况只会是共有三个运算符且前面都衔接,只需要比较最后一个的second
if(a[second1].equals(b[second2])){//最后一个操作数是否重复
return true;
}else{
break;
}
}
if(list1.size()==1){//上面已经解决了2、3个运算符的算式重复的情况,现在补充只有一个字符且重复的情况,能执行到这怎么重复
return true;
}
}
return false;
}
四.模块性能分析
五.单元测试
1.参数异常测试
2.查重测试
3.操作数运算符生成测试
4.最终结果测试
5.答题测试
6.测试覆盖率
五.结论
通过这些测试用例,程序被验证能够生成正确的自然数和分数,且生成的表达式符合四则运算的规则:
- 数字和分数生成都在指定的范围内。
- 假分数能够正确转换为真分数。
- 不会出现无效的零分母或负数。
- 测试用例全面涵盖了程序的边界情况和正常情况,确保生成的四则运算表达式是有效的
六.项目小结
1.每道题目中出现的运算符个数我们只实现了单个运算符,当我们后来试图扩展多个运算符的时候发现时间不够了,因此只能上交较为简单的版本。
2.查重功能以我们的算法和我们的能力感觉实现有难度。
3.遇到的困难主要是数组越界,通过严谨的检查以及步步验证的方式找出了错误并解决了。另一个须待解决的问题是生成题目的速度有些缓慢,因此完善了多次的算法来提高代码的执行效率。
4.做完这次项目后发现先做需求分析文档和先确定所需要类再去开始写程序的重要性,否则在项目过程中会出现需要多次修改数据结构的问题
5.总的来说,在结对编程中我们有各自的想法,通过代码的形式来进行人与人之间的交流不失为一种好的方法,在这个过程中我们培养了团队协作的能力和与他人交际的能力,同时也促使自身的编程能力不断提高,这使我们都受益匪浅。当然如果还有机会的话,我还是希望可以实现带括号的运算式的生成以及答案的计算。
标签:结对,题目,项目,int,操作数,运算符,symbol1,dataNode From: https://www.cnblogs.com/st0rmy/p/18639664