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思想的一个单元,这个单元的作业以求导为主题,从一开始的加减多项式求导再到最后的嵌套多项式求导,难度逐渐提高,编 ...
随机推荐
- xshell使用技巧
XShell是一款Windows下的一款远程连接Linux主机的工具,类似的软件还有SecureCRT,putty等,但是个人感觉XShell好用,功能强大.. 一.复制和粘贴 linux的Shell ...
- WordPress 伪静态规则(IIS/Apache/Nginx)
不少朋友总是询问 WordPress 如何添加伪静态规则,今天倡萌就总结一下 Apache/Nginx 三种环境下的伪静态规则,希望对大家有所帮助. 检测主机是否支持伪静态的方法:在WP后台 > ...
- 【NLP】常用优化方法
目录 梯度下降法 动量法 AdaGrad算法 RMSProP算法 AdaDelta算法 Adam算法 1.梯度下降法 梯度下降法可以分为三种,批量梯度下降法(BGD).小批量梯度下降(MBGD).随机 ...
- Java使用Netty实现简单的RPC
造一个轮子,实现RPC调用 在写了一个Netty实现通信的简单例子后,萌发了自己实现RPC调用的想法,于是就开始进行了Netty-Rpc的工作,实现了一个简单的RPC调用工程. 如果也有兴趣动手造轮子 ...
- 校园网络 luogu P2812 (又是强联通)
题目传送门!(luogu) 首先考虑问题一 不难想到,如果有一个学校作为终端机,那么跟其处于同一个强联通中的所有学校就可以不用作为终端机了. 那么,问题一也就迎刃而解了:找到所有入度为0的缩点.因为这 ...
- [Unity2d系列教程] 006.Unity如何根据图片自动生成Animator
Unity制作2D产品的时候,我们在制作动画的时候,要不断的生成Animation,Animator等等资源,如果动画一多的话,就变得麻烦.由于Unity是支持插件开发的,我们可以添加一个Editor ...
- Android 中加载本地Html 跨域问题,http协议允许加载
一.需求: 后台加载HTML的包时间太长,太卡,让把所有的HTML包放到前台:使用的是file://协议,有些内容和样式加载不出来,H5那边说需要用http://协议来加载: 二.处理过程: 安卓最简 ...
- Chrome自带全网页截图
1.等待网页打开完毕 2.组合键 ctrl+shift+i 打开开发者工具 3.按 ctrl+shift+p 调出一个面板 4.输出 full 5.在下一行出现 capture full size s ...
- 自动化测试: Selenium 自动登录授权,再 Requests 请求内容
Selenium 自动登录网站.截图及 Requests 抓取登录后的网页内容.一起了解下吧. Selenium: 支持 Web 浏览器自动化的一系列工具和库的综合项目. Requests: 唯一的一 ...
- Java实现 LeetCode 746 使用最小花费爬楼梯(递推)
746. 使用最小花费爬楼梯 数组的每个索引做为一个阶梯,第 i个阶梯对应着一个非负数的体力花费值 costi. 每当你爬上一个阶梯你都要花费对应的体力花费值,然后你可以选择继续爬一个阶梯或者爬两个阶 ...