OO第一单元——谜之随性总结
前言
第一单元的作业主要是以多项式求导为载体来训练我们的面向对象的思维,难度循序渐进,复杂度也一直在提高,但是面向对象的体现性也越来越强,当然带来的优势与便利也在逐步提升。下面的内容主要从需求分析,代码结构与框架,复杂度分析,如何测试四个方面来对每一次作业进行总结。
第一次作业
需求分析
第一次作业需要我们对简单多项式进行求导,只需要支持简单的幂函数加上常数项即可,且项与项之间只有加法和减法,难度并不是很大。
代码结构与框架
写第一次作业时我竟然神奇地忽略了指导书中的正则表达式指导,并且本身对其的使用并不是很了解,便没有使用正则表达式对输入进行处理,而是使用简单粗暴的情况判断对整行的输入进行了一个读取。所以大部分篇幅都是对输入的处理上。因为多项式的结构比较简单,只是新建了一个项类,用于存储该项的常数项系数,幂函数的指数项。大致处理过程就是一个项一个项的读入,放入hashmap中,放入的时候合并同类项,当整个表达式都读取完毕后,再从hashmap中取出来进行逐项求导,求导后再放入一个待输出的hashmap中。因为要是输出的长度尽可能的短,便加上了一个比较长的输出处理函数,先输出正的项,最后输出负的项,并且对一些能省略的符号都进行省略。所以最后得到的程序就是两个大类,一个是项类,一个就是集各种功能于一身的主类。
复杂度分析
因为不涉及多个类之间的调用,仅是一个类之间函数的调用,所以循环依赖和继承树的深度都为0。但是由于输入处理没有采用正则表达式,所以带来的循环与条件语句显得比较复杂。
如何测试
本次采用了一向使用的自己自动生成数据测试的测试方法,由于没有使用过python,所以自己用java写了一个自动生成测试程序的代码,可以随机的生成测试数据。
因为种类较多,所以随机生成数据的代码较长。
import java.util.Random; public class MainClass {
private static int op1;//+-
private static int op2;//+-
private static int op3;//m
private static int op4;//x
private static int op5;//**
private static int op6;//+-
private static int op7;//n public static void main(String[] args)
{
int col = 0;
while (col < 80)
{
print_Symbol();
print_Space();
print_coefficientSymbol();
print_coefficient();
print_Space();
print_multiply();
print_Space();
print_x();
print_Space();
print_power();
print_Space();
print_indexSymbol();
print_index();
print_Space();
col++;
}
} public static void print_Symbol()
{
Random rd = new Random();
op1 = rd.nextInt(2);
if (op1 == 0)
{
System.out.print('+');
}
else
{
System.out.print('-');
}
} public static void print_Space()
{
Random rd = new Random();
int op = rd.nextInt(3);
while (op > 0)
{
System.out.print(" ");
op--;
}
} public static void print_coefficientSymbol()
{
Random rd = new Random();
op1 = rd.nextInt(3);
if (op1 == 0)
{
return;
}
else if (op1 == 1)
{
System.out.print('+');
}
else
{
System.out.print('-');
}
} public static void print_coefficient()
{
Random rd = new Random();
if (op1 == 0)
{
op2 = rd.nextInt(2);
if (op2 == 0)
{
return;
}
}
op2 = 1;
int length = rd.nextInt(1) + 1;
StringBuilder sb = new StringBuilder();
while (length > 0)
{
int number = rd.nextInt(3);
sb.append(number);
length--;
}
System.out.print(sb.toString());
} public static void print_multiply()
{
Random rd = new Random();
if (op2 == 1)
{
op3 = rd.nextInt(2);
if (op3 == 0)
{
return;
}
else
{
System.out.print("*");
}
}
} public static void print_x()
{
Random rd = new Random();
if (op3 == 1)
{
op4 = 1;
System.out.print("x");
}
else if (op2 == 1)
{
op4 = 0;
return;
}
else if (op1 != 0)
{
System.out.print("x");
op4 = 1;
}
else
{
op4 = rd.nextInt(2);
if (op4 == 0)
{
return;
}
else
{
System.out.print("x");
}
}
} public static void print_power()
{
Random rd = new Random();
if (op4 == 0)
{
op5 = 0;
return;
}
else
{
op5 = rd.nextInt(2);
if (op5 == 0)
{
return;
}
else
{
System.out.print("**");
}
}
} public static void print_indexSymbol()
{
if (op5 == 0)
{
op6 = 0;
return;
}
else
{
Random rd = new Random();
op6 = rd.nextInt(3);
if (op6 == 0)
{
return;
}
else if (op6 == 1)
{
System.out.print("+");
}
else
{
System.out.print("-");
}
}
} public static void print_index()
{
if (op5 == 0)
{
op7 = 0;
return;
}
else
{
Random rd = new Random();
int length = rd.nextInt(1) + 1;
op7 = 1;
StringBuilder sb = new StringBuilder();
while (length > 0)
{
int number = rd.nextInt(3);
sb.append(number);
length--;
}
System.out.print(sb.toString());
} }
}
第一次作业出现的一个bug在输出的处理上,x**-1次方输出时为了简便漏掉了一个判断选项,导致输出-x,在互测时惨遭毒手,同一个x**-1被hack了18次。
第二次作业
需求分析
第二次作业在第一次的基础上迭代增加了三角函数类,并且一个项之间增加了乘法的运算,即输入一个项时不会是简单的一个幂函数加上常数项的形式。并且这次作业加上了异常处理的需求,即在输入不符合表达式结构的式子时需要输出WRONG FORMAT!
代码结构与框架
这次看到了正则表达式指导的文档,并在输入处理上采用了正则表达式的形式,一下子降低了输入处理的复杂度。第二次作业采用的策略是先逐项读取,再进行因子分析,即先利用正则表达式一个一个项进行读取,再从每个项中分出因子,因为总共只有四类因子,即常数因子,幂函数因子,三角函数的两类因子。所以新建了一个项类专门管理每个项。之后的求导与输出便和第一次作业的处理相类似,因为观察到每个项的求导形式固定,所以仅需一个求导函数即可对整个项进行求导。求导后得到的新的项仍然存在hashmap中。不过这次的化简处理较为复杂,而本人仅对于平方和为一的条件进行展开并化简,但不能化到最简,因为会涉及到大量的递归处理。
而对异常输入的处理也放在了input类中,利用正则表达式进行判断,如果没有找到符合正则表达式的式子,则直接输出WRONG FORMAT!如果找到了符合条件的最长表达式但是不是原表达式则同样输出异常。
复杂度分析
因为这次作业没有涉及到类之间的多重调用,所以复杂度仍然没有体现性。
如何测试
第二次作业的测试方法完全使用了全自动的测试方法,即利用强大的python工具实现对代码的自动测试,随机生成数据的采用了python的xeger包,即可根据正则表达式随机生成想要的数据,并利用windows批处理工具加上python代码实现正确性的自动对拍。
这次自己的程序并没有出现bug,而互测屋里的其他同学都或多或少的出现了bug,大多都是在一些细节的处理上。例如有的同学-1仅仅输出了一个负号,还有的同学项与项之间在特定情况下少了一个符号,还有一个同学在特定情况下结果总会多出一个sin(x)。
第三次作业
需求分析
第三次作业一下子加大了难度,在第二次作业的基础上迭代增加了递归的操作,并且增加了表达式因子,即引入了对括号的处理。即三角函数里的括号里的内容可以无限递归下去。
代码结构与框架
第三次作业的输入处理仍然延续采用了正则表达式的结构,不过需要对表达式进行预先的处理。格式检查这一操作则放在整个程序的第一步,这次的格式检查难度也极大地提升了,不能是简单的字符串匹配,而是要加上递归的检查与处理,即先将所有的表达式因子转换成同等的字符,在每次检查时去掉嵌套,再进入嵌套中进一步检查,从而达到从外到内检查整个表达式的目的。
在检查格式无误的情况下,再将整个表达式中的空白字符全部删除,再进行输出处理与求导操作。
这次主要是利用了各类函数共同实现求导接口的方式来对整个表达式来进行求导。同时也采用了层次化的思想来完成对整个作业的处理。即将整个表达式看成项之间的依次加减叠加,每个项内各个因子的相乘叠加,因子之内的嵌套叠加,从而求导时按照此规律递归求导。这次并没有利用任何结构去存取相关的项,因子或系数等,直接用一个待输出的表达式存取递归求导返回的表达式。最后便可在这个求导后得到的表达式上进行化简的处理。
复杂度分析
本次作业的复杂度主要体现在了类之间的循环递归调用的层面上。
如何测试
本次由于表达式是递归结果,直接由python的xeger包是不能生成的,需要使用一定的技巧来控制生成,并且只需要加入一些控制变量即可控制嵌套的深度等。主要采用了表达式替换的策略,即将可以嵌套的地方用符号标记,再从标记的地方递归生成表达式,当达到指定嵌套深度时,停止表达式的继续嵌套。
import random
from xeger import Xeger
fo = open("raw_poly.txt", "w")
expressionRegex = "^(@[+-]{1,2})*@$" termRegex = "^(#\\*)*#$" sinFactorRegex = "^[ \\t]*sin[ \\t]*\\(~\\)([ \\t]*\\*\\*[ \\t]*(\\+)?[1-9]\\d{0,1})?$" cosFactorRegex = "^[ \\t]*cos[ \\t]*\\(~\\)([ \\t]*\\*\\*[ \\t]*(\\+)?[1-9]\\d{0,1})?$" powerFactorRegex = "^[ \\t]*x[ \\t]*([ \\t]*\\*\\*[ \\t]*(\\+)?[1-9]\\d{0,1})?$" constFactorRegex = "^[ \\t]*[+-]?(([1-9]\\d{0,1})|0)$" exprFactorRegex = "^\\(!\\)$" x = Xeger(limit=2) def generate(): max_round = 2 result: str = x.xeger(expressionRegex) generate_round = 0 while True: generate_round += 1 for termCount in range(result.count('@')): result = result.replace('@', x.xeger(termRegex), 1) for factorCount in range(result.count('#')): factor_type = random.randint(0, 4) if factor_type == 0: if generate_round > max_round: result = result.replace('#', x.xeger(powerFactorRegex), 1) else: result = result.replace('#', x.xeger(sinFactorRegex), 1) elif factor_type == 1: if generate_round > max_round: result = result.replace('#', x.xeger(powerFactorRegex), 1) else: result = result.replace('#', x.xeger(cosFactorRegex), 1) elif factor_type == 2: result = result.replace('#', x.xeger(powerFactorRegex), 1) elif factor_type == 3: result = result.replace('#', x.xeger(constFactorRegex), 1) elif factor_type == 4: if generate_round > max_round: result = result.replace('#', x.xeger(powerFactorRegex), 1) else: result = result.replace('#', x.xeger(exprFactorRegex), 1) for innerCount in range(result.count('~')): factor_type = random.randint(0, 4) if factor_type == 0: if generate_round > max_round: result = result.replace('~', x.xeger(powerFactorRegex), 1) else: result = result.replace('~', x.xeger(sinFactorRegex), 1) elif factor_type == 1: if generate_round > max_round: result = result.replace('~', x.xeger(powerFactorRegex), 1) else: result = result.replace('~', x.xeger(cosFactorRegex), 1) elif factor_type == 2: result = result.replace('~', x.xeger(powerFactorRegex), 1) elif factor_type == 3: result.replace('~', x.xeger(constFactorRegex), 1) elif factor_type == 4: if generate_round > max_round: result = result.replace('~', x.xeger(powerFactorRegex), 1) else: result = result.replace('~', x.xeger(exprFactorRegex), 1) for exprCount in range(result.count('!')): result = result.replace('!', x.xeger(expressionRegex), 1) if result.find('@') == -1 and result.find('#') == -1 and result.find('~') == -1 and result.find('!') == -1: break return result str = generate()
fo.write(str + "\n")
这次程序出现了两个本不该出现的bug,在检查输入式子格式的时候竟然把cos的最后一个字母当成了n,导致如果输入中cos后嵌套的表达式中出现格式错误将忽略。还有一个bug就是为了减少括号而在表达式递归加减时没有对后面的表达式套上括号,这样就导致了如果括号外面是负号,如果括号里面是多个式子时就会出现负号的错误。
在互测阶段仍然是使用自动测试程序对他人的程序进行测试,大多数bug都是在多重嵌套是细节上出现了错误。
总结与反思
在第一单元的作业练习中,虽然并没有淋漓尽致地将面向对象的思想应用到作业当中,但在思考与体验的过程中也慢慢地领略了面向对象的思维特点与处理方法,并在和老师同学助教的交流中受益匪浅,也学会了一些重要的操作,更是对java语言的进一步了解与熟悉。相信在后续的oo作业中,能尽最大可能地将面向对象的思维应用到其中去。
OO第一单元——谜之随性总结的更多相关文章
- 【作业1.0】OO第一单元作业总结
OO第一单元作业已全部完成,为了使这一单元的作业能够收获更多一点,我回忆起我曾经在计算机组成课设中,经常我们会写一些实验报告,经常以此对实验内容反思总结.在我们开始下一单元的作业之前,我在此对OO第一 ...
- OO第一单元(前四周)作业总结
OO第一单元(前四周)作业总结 OO第一单元(前四周)作业总结要求(第四次作业) 0.前言 本次博客针对的是本人学习Java的第一阶段的三次作业的作业总结 第一次作业的内容是:7-1 计算税率 (20 ...
- 北航OO第一单元作业总结(1.1~1.3)
经过了三次作业之后,OO第一单元告一段落,作为一个蒟蒻,我初步了解了面向对象的编程思想,并将所学内容用于实践. 一.第一次作业 1.架构分析 本次作业需要完成的任务为简单多项式导函数的求解.表达式仅支 ...
- OO第一单元总结与反思
OO第一单元总结与反思 目录 OO第一单元总结与反思 摘要 第一次作业 本次作业UML类图 本次作业度量分析 第二次作业 本次作业的UML类图 本次作业的度量分析 第三次作业 本次作业的UML类图: ...
- OO第一单元作业总结
oo第一单元的作业是对多项式的求导.下面就是对三次作业分别进行分析. 第一次作业 分析 第一次作业相对来讲比较简单,甚至不用面向对象的思想都能十分轻松的完成(实际上自己就没有使用),包含的内容只有常数 ...
- OO第一单元总结
OO第一单元作业总结 一.前言 开学四周,不知不觉已经做了三次OO作业.事实上,每一次作业对我来说都是很大的挑战,需要花费大量的时间和精力来学习. 虽然学得很艰苦,但最后还是连滚带爬地完成了.(好惨一 ...
- OO第一单元优化博客
OO第一单元优化博客 第一次作业: 合并同类项+提正系数项+优化系数指数0/1=满分 第二次作业: 初始想法 一开始是想以\(sin(x)\)和\(cos(x)\)的指数作为坐标,在图上画出来就可 ...
- 【OO学习】OO第一单元作业总结
OO第一单元作业总结 在第一单元作业中,我们只做了一件事情:求导,对多项式求导,对带三角函数的表达式求导,对有括号嵌套的表达式求导.作业难度依次递增,让我们熟悉面向对象编程方法,开始从面向过程向面向对 ...
- OO第一单元(求导)单元总结
OO第一单元(求导)单元总结 这是我们oo课程的第一个单元,也是意在让我们接触了解掌握oo思想的一个单元,这个单元的作业以求导为主题,从一开始的加减多项式求导再到最后的嵌套多项式求导,难度逐渐提高,编 ...
随机推荐
- 关于mobileSelect.js日期数据获取封装,动态时间,封装
传入起始年份和起始月份 得到 插件的标准格式放到 效果 let getAllDatas = (stime, etime) => { //接收传进来的参数月份 var data_M = etime ...
- 对 getopts 的理解
getopts 格式 1 #!/bin/bash 2 echo "begin index is $OPTIND" 3 echo "begin ARG is $OPTARG ...
- springboot系列——重试机制原理和应用,还有比这个讲的更好的吗(附完整源码)
1. 理解重试机制 2. 总结重试机制使用场景 3. spring-retry重试组件 4. 手写一个基于注解的重试组件 5. 重试机制下会出现的问题 6. 模板方法设计模式实现异步重试机制 如果有, ...
- Kubernetes笔记(四):详解Namespace与资源限制ResourceQuota,LimitRange
前面我们对K8s的基本组件与概念有了个大致的印象,并且基于K8s实现了一个初步的CI/CD流程,但对里面涉及的各个对象(如Namespace, Pod, Deployment, Service, In ...
- JavaScript (四) js的基本语法 - - 函数练习、arguments、函数定义、作用域、预解析
个人博客网:https://wushaopei.github.io/ (你想要这里多有) 一.函数练习 1.求最值 // - 求2个数中的最大值 function getMax(num1, nu ...
- Java实现 蓝桥杯 历届试题 小计算器
历届试题 小计算器 时间限制:1.0s 内存限制:256.0MB 问题描述 模拟程序型计算器,依次输入指令,可能包含的指令有 1. 数字:'NUM X',X为一个只包含大写字母和数字的字符串,表示一个 ...
- Java实现 蓝桥杯VIP 算法训练 数组查找及替换问题
描述 给定某整数数组和某一整数b.要求删除数组中可以被b整除的所有元素,同时将该数组各元素按从小到大排序.如果数组元素数值在A到Z的ASCII之间,替换为对应字母.元素个数不超过100,b在1至100 ...
- Java实现蓝桥杯突击战
突击战 你有n个部下,每个部下需要完成一项任务.第i个部下需要你花Bi分钟交待任务,然后他会立刻独立地. 无间断地执行Ji分钟后完成任务.你需要选择交待任务的顺序, 使得所有任务尽早执行完毕(即最后一 ...
- java实现 洛谷 P1540 机器
import java.util.LinkedList; import java.util.Scanner; public class Main { private static Scanner ci ...
- (八)DVWA之SQL Injection--SQLMap&Burp测试(Medium)
一.测试需求分析 测试对象:DVWA漏洞系统--SQL Injection模块--User ID提交功能 防御等级:Medium 测试目标:判断被测模块是否存在SQL注入漏洞,漏洞是否可利用,若可以则 ...