wzy2001wzy

导航

BUAA面向对象2022第一单元总结

BUAA面向对象2022第一单元总结

总览

作业内容

本单元的主要作业内容为表达式拆括号,共有3次作业,为迭代开发。

第一次作业只有加减乘次方以及单层括号。

第二次作业加入了嵌套括号,简单三角函数,自定义函数和求和函数。

第三次作业加入了嵌套三角函数和嵌套自定义函数。

完成情况

我在三次作业中使用了递归下降法,坚持迭代开发,没有进行过重构。

三次均有bug,但是都满分通过了强测。(这强测是真的弱)

性能分:在第一次作业中获得满分,第二三次作业中由于没有进行足够的三角优化,扣了不少

互测情况:三次作业 发起/受到hack 分别为 2/12 , 2/3 , 5/3

bug分析

第一次作业:在输出第一个正项时,如果是常数项,会多输出一个*

第二次作业:遇到sin(-1)**2时,直接把符号提了出来,即-sin(1)**2

第三次作业:遇到sin(sin(-1))时,会把里层括号的负号算2次,即sin(sin(1))

纯nt

实现过程

总体思路

先将输入的自定义函数和表达式经过一定的处理,后使用parser和lexer对表达式进行递归下降解析。

利用字符串整体替换并加一层括号实现函数的调用。

使用两层HashMap对结果进行存储,便于合并同类项。

UML类图

 

 

 

 

UML类图解释

除了接口的实现,我把联系紧密的类用直线连了起来。

MainClass:输入与输出

ChangeString:去掉空白符以及将多字符的符号(例如**)换成特定单字符符号(例如^),便于lexer和parser解析

Lexer:扫这个表达式

Parser:对表达式进行递归下降,当遇到不同的符号/数字时,执行不同的解析方法。

Expr:表达式,由若干项组成,+连接,startFh为第一个符号。

Term:项,由若干因子组成,*连接,包含了startFh为第一个符号。

Factor:因子,分为常数因子,变量因子,三角函数因子,自定义函数因子,求和函数因子,表达式因子。其中getAns()方法会返回化简后的表达式。

Number:常数因子,由一个常数组成。

Variable:变量因子,由x和指数组成。

SanJiao:三角函数因子,由三角函数类型和内部表达式以及指数组成。

FindVariable:找出自定义函数和求和函数中由,分隔的各个'项'。

ZiDingYi:自定义函数因子,经过替换处理后看作表达式。

Sum:求和函数因子,经过替换处理后看作表达式。

SimpleFactor:化简后的因子。

Polynomial:化简后的多项式。

Node:化简后的三角函数内部的玩意。

这里对Polynomial和Node进行一些额外的说明。

Polynomial中的第一层HashMap的key值为化简后的各个项,value为这些项的乘积的系数。

即:(Value:coeff)(Key:*sin(X)^a*...*cos(Y)^b)

第二层HaspMap的key值为某个sin(X)^exp中的X,value为其中的exp

在第二次作业中X一定可以用a*x^b表示,因此我用两个变量将a,b存储。

可以发现这样存储之后对于Polynomial的运算会很方便。

在第三次作业中,由于X可以是一个Polynomial,但是我发现只需要将Node中的a,b变成一个Numbe/Variable/Polynomial(也就是SimpleFactor)就可以沿用之前的所有运算操作,不需要任何其他的改变。

结果化简与输出

对于sin(0)直接返回0,cos(0)返回1。

对于sin内部第一项系数为-,将其内部取反外部加负号。

cos同理,只是外部不加负号。这样可以消掉一些恰好为相反数的项。

输出时采用递归输出,对于三角函数,可以判断其内部是否是一个常数或是一个系数为1的因子,如果是则只用套一层括号。

 

复杂度分析

代码总行数:841

 

优点:每个类想实现的功能比较清晰,类之间的耦合度较低。

缺点:有些类在实现起来的时候实在是过于丑陋,以至于写出了bug

可以看到,在方法复杂度中,采用了较多if的方法复杂度较高,事实上我的错误也都错在这些方法。

第一次是Polynomial.toString(),二三次是SanJiao.getAns()。

因此提高代码的结构化是降低bug出现概率的重要手段。

总结与反思

代码架构

这次我对自己的代码整体架构还比较满意。在第二次到第三次的迭代中,我几乎没有进行太多修改就完成了任务。不过这主要还是因为递归下降的板子写的好,如果让我自己写,我很可能写不出来。

当然我也有一些不足,比如搞了ChangeString和FindVariable这两个奇怪的类,其实我只是为了写一个静态方法。还有就是Polynomial的运算实际上只用传一个参数,我传了两个,就看起来很蠢。

关于互测

其实我并没有认真读别人的代码,只是用了一些看起来容易错的数据,然后就hack到了一些人。

反思

这三次的bug实在是不应该。虽然都是在优化的时候写出来的bug,但是bug都非常明显。这说明我写代码和测试时都不够认真。

一些建议

可以把性能分最高的结果展示出来。

可以加一些额外任务,例如不合法表达式的判断,sum函数的嵌套等(作为额外的测试点),这样卷王们就有更多事情可以去做了。

可以把一些hack成功的数据再给所有人测一遍。

posted on 2022-03-23 13:52  我没有名称  阅读(65)  评论(0编辑  收藏  举报