OO 表达式求导 小结

第一部分 oo作业分析

1.类图

程序的大致结构如下:

 

2.性能分析

 

在第一次写的过程中,由于对java面向对象方式的不熟悉,导致有的类写的过长,processFirst1,findOperator函数复杂度过高,究其原因,是使用了较多的if判断语句,条件判断也过深。processFirst1解决的是处理首项符号的问题,我是使用判断前两个是否是+-,如果同时是加减,则合并成一个符号。其实,现在发现更优化的方法是,把所有形式直接补充成标准形式,即开头为两个运算符的形式,这样,所有的项都能按照统一的形式处理。findOperator函数的目的是将式子按运算符分隔开,因此有很多的条件判断语句。我的处理方法是从头遍历一遍字符,再通过一些条件判断+,-是否是运算符,而这种方法必然要用到很多if,else语句,由于笔者能力有限,暂时未想到更好的解决方法,希望有dalao能提出更好的解决方法。

 

第二次作业

1.类图

程序的大致结构如下:

 

2.性能分析

 

 

第二次作业是在第二次作业的基础上增加了sincos的求导,我的总体思路是每一个都化为constant*x^a*sin(x)^b*cos(x)^c,然后我事先对这个公式的求导进行了数学推导,直接使用这个推导后的公式进行求解。总的来看,我的代码还是和c语言挺像的,没有完全转向面向过程,对class的分类也不是很合适。

第二次作业大部分代码还是基于第一次作业,尤其是解析表达式阶段,仍旧用相同的方法找运算符,判断非法空格,因此圈复杂度和嵌套深度还是很高。

第三次作业

1.类图

程序的大致结构如下:

 

2.性能分析

 

 

第三次作业是最复杂的一次,几乎包含对任意表达式的求导,也支持括号和表达式因子。刚看时我也懵了,这表达式我手算都算不出来,让我写代码算?

然后,作业发布的那天晚上,我想了一个晚上。我开始把式子分解为两个部分。表达式由项组成,我就首先把表达式分成了项,我用Parse类处理了这个类,并且用Arraylist存储了每一个项(class Rawpoly),而每一个项是一些因子相乘,而因子又可以是表达式(class Parse),这样貌似我们就进入了一个死胡同:Parse->Rawpoly->Parse->Rawpoly->...,因此我又定义了一个BasicPoly类,专门在项里匹配最简单的形式--常数和x^a(含省略形式),这样我们的递归就能最终到BasicPoly结束。

但是,问题又出现了......

这种思路对没有cossin的式子是完全行的同的,可是我们还有cossin啊,它们的内层甚至还能进行嵌套,比如cos((x+1))。那又怎么处理呢?

聪明的你一定会有一些思路吧。下面说说我的解决方法。我是在Parse类里定义了一个tag,来表征表达式的类型。我用tag=5来表示最常规的表达式,用tag=4表示costag=3表示sin

tag的引入,使我们对不同式子的求导表达式进行了一些区别,而对sin,cos,我们对内部内容用普通规则拆分(我们之后对sincos求导要用到内部表达式求导),其方式跟普通表达式一样。

由于时间和能力有限,我对表达式几乎没有进行化简。这也是本次作业的不足之处。

第二部分 所谓的BUGHack

Bug?

Bug,Bug,

Where are you?

下面邀请你来到消灭bug的游戏中,我们游戏的宗旨是让bug像头发一样越变越少(不可能的,你休想夺走我的头发

在这三次的游戏中,笔者性能分损失的很惨重,还因一个点被hack6次!

第一次没有考虑到首项要是为负数,可以和其他项调整一下顺序使首项为正,以减小长度,因此性能没有达到最优。

第二次没有想到像其他大神一样用启发式算法,只是稍稍合并了sin(x)^2+cos(x)^2=1。性能分也不高。

不过所幸前两次逃过了bug君的追杀,不过古人言“常在河边走,哪有不湿鞋”。第三次,我错误的认为在replace中用\\v,然后就被hack到了。第三次,我几乎处于没有优化的状态,性能分也挺低的。

 

如何找Bug?

正所谓写码一时爽,互测火葬场......

下面向你介绍一下在hack部分我的游戏攻略:

1WRONG FORMAT部分

\f \v首先需要警惕,指导书上说了只包括空格和\t,因此trim要谨慎使用。测试中的错误大致还是出现在对题意空格理解的不精确。很多对\f没有进行判断就直接trim

另外一个点是很多人都没忘记判断乘方的时候符号和数字之间也不能有空格。

在第二次作业中,对sin(x)格式理解也需要准确,sin之间不能有空格,但是和((x之间能存在空格。

这些细节的理解往往是导致WF的重要原因,当然,还有像我一样,不知道打\\v,还是\v,还没去试的......

(2)计算错误

这个很少见,一般来说导致的原因是表达式解析导致的错误,比如首项判断符号最后忘了加进去,或者写着写着就忘了符号。还有就是,输出模块存在一些问题。

(3)如何构造测试样例

许多大佬的方法是直接造测评机,随机生成正则表达式,再随机添加空格和去掉符号。不得不说,这个方法很有效,但是首先你得把测评机造出来呀(有大佬在讨论区分享了怎么造表达式,挺详细的)!

作为非dalao人士,我选择手动构造。构造的点也是基于我上文中提到了错误类型。一般来说WF的错误出现的比较多,可以在你的表达式中随意的加一下空格和非法字符。至于计算错误,就构造一些有各种运算类型的表达式,还有就是边界条件。

在这次作业中,matlab是计算的一个很好的工具,面对一堆很长的表达式,可以快速验证结果是否正确。

第三部分 Applying Creational Pattern

我们刚学了继承,多态,接口,接口比较适合用在这次作业中。

我们可以创建表达式接口,让所有的表达式,项,因子都继承表达式接口,它们都应该具有求导,合并等方法,我们可以写在接口中,再具体去实现。

第四部分 总结

(1)性能优化部分还需加强

(2)if的嵌套不能过深

(3)分类要合理,代码重复利用率要变高