北航24年oo第一单元总结

一、程序结构

1.hw1

沿袭training1的做法,在第一次作业的构造中使用了Lexer类(用于将字符串拆分为不同的Token)和Parser类(用于按照形式化表述解析表达式)。

对表达式的不同层次,建立了ExprTerm以及Factor三个类和接口,其中Factor接口被VariableFactorConstantFactor以及ExprFactor三个类实现,这三个类在形式化表述中都属于因子。

此外,为了进行展开,化简以及最终的输出,在分析作业要求后得出本次作业的最终输出结果一定是一个ax^b形式的表达式,因此创建了Polynomial类用于计算以及输出。

2.hw2

hw2在hw1的基础上增加了指数函数因子以及自定义函数的要求。

首先由于形式化表达的变更,在Expr包下面添加了FuncFactor以及ExpFactor两个因子类,这两个类的逻辑与之前的类没有区别。

由于自定义函数,我创建了Function工具类,用于存储函数信息并且负责在最终计算时将参数带入函数当中。

指数函数的添加导致最终输出不再是简单的多项式形式,而是ae^Cx^b形式,所以添加了Index工具类,用于存储exp以及x的两个指数的值。在这一部分,我认为我的设计不如其它同学的单项式-多项式设计,单项式的设计可以使得从hw1到hw2中不需要更改多项式类中的内容而只需要变动单项式类即可。

此外为了一定程度的化简,需要求BigInteger的多项式,所以我建立了一个MyMath类(后来发现BigInteger有自己的gcd方法...)。

3.hw3

hw3只添加了函数嵌套的允许以及求导因子,其中函数嵌套在hw2的处理中以及实现而求导因子也只需要添加一个DeriFactor类即可,求导方法只添加在多项式类中。

二、架构设计体验

三次作业中,第一次作业是借鉴训练的代码实现,第三次作业实在已经成型的第二次作业的基础上添加,在架构设计中,我只有第二次作业进行了许多修改。

第二次作业设计中最重要的部分就是多项式的设计,最开始我的想法比较不成熟,想要将最终答案修改为(ae^A+be^B)x^b形式。在实现代码并通过测试后,我又觉得(ax^b+cx^d)e^A形式更好,因为这样我就不需要改动第一次作业中的Poly类的内容,我也这样去做了。

但是在研讨课上,我突然发现可以以ae^Cx^b的形式来表示多项式,这样的扩展性非常强,无论是加入三角函数还是不同变量都可以很好地实现,所以我的最终方案也是如此。不过正如我前面所说,我的实现不如单项式-多项式方法,可扩展性也更低。

比如在添加y和z时,我不仅要在Index类中添加相应的指数,修改各种方法,还要在Poly类中修改相关的toString函数。而如果使用单项式-多项式的构造,多项式类只负责组合单项式,那么就只需要修改单项式即可。

三、bug分享

在三次作业中我只出现了一个bug。

致敬传奇数据:

0
(((((((((((x^8)^8)^8)^8)^8)^8)^8)^8)^8)^8)^8)^8

没有注意小细节,我的Index类中,用于存储x的指数的变量使用的是int类。

四、hack策略

Hack策略只有一个:评测机。

在第一次作业中,我的评测机主要用于测试自己以及同学们的代码正确性,并没有为互测进行设计。所以在我跑出了三位同学的错误输入的情况下,我仍然没能hack到任何一人(

在第二次作业中,我对自己的评测机进行了cost限制的添加,将cost限制在互测级别,同时也限制了强测的cost(导致被传奇数据hack了)。所以这一次测试我测试出了三个同学的4个不同质问题。由于不是观看代码,是否同质只能看报错是否相同(答案错误和格式错误还有运行错误大概率不是同质的)。

第三次作业太过简单,所以我也没有怎么修改评测机,大家也没有什么大的错误。

五、优化

1.先是性能优化(性能分)

第一次作业的优化只有一个,就是在出现-1+x形式的输出时将正的项提到第一项,减少一位的输出。这一次作业大部分人也拿到了满分。

第二次作业的优化有许多,我将其分为五层:

  • 第一层:只进行第一次作业的优化,exp后面无脑跟两重括号

  • 第二层:对exp的括号进行修改

  • 第三层:对exp内的各项进行提公因式,如exp((10*x+10*x^2))可以被优化为exp((x+x^2))^10

  • 第四层:在提公因式时注意到提出的数字不同,可能导致长度更短。如:exp((32+32*x+48*x^2))按照第三层的优化会变为exp((2+2*x+3*x^2))^16,然而exp((4+4x+6x^2))^8会更短。

  • 第五层:主要到部分情况可以将exp拆成几个部分,使得整体变短。如:exp((1+1000000*x+1000000*x^2))可以变为exp((x+x^2))^1000000*exp(1)

我再第二次作业中处理到了第四层,因为第五层的优化情况很极限,而且应该不会很简单(但是课题组还是出了相关数据放在强测中)。

第四层的处理看似需要遍历gcd的所有因子来比较长度,但是我数学证明出来只有将gcd的个位数因子提回exp中,表达式才可能变短(证明放在最后)。也就是说,如果最大公因子为100,那么exp的次方只有是50,25,20才有可能更短,这样就减少了遍历的时间。(可能还是有更加强的条件,但是我觉得这样就足够了)。

第三次作业同第二次作业。

2.还是性能优化(速度)

第二次作业的时候,可能由于每个人的具体实现不一样,同学之间就算构造相同,运行大型数据跑出来的时间也不同(甚至跑不出来)。所以我就对我的代码进行了一个比较大的优化。

分析发现,运行时间最长的就是Poly里面的toString方法,因为Poly拥有Index,而Index内也有Poly。导致进行一次toString计算需要调用许多层toString,而且同一个Poly就算没有任何变动也会被调用许多次toString,浪费性能。

因此,我将toString方法改为了calc方法,添加string属性,在必要的时候调用calc方法对多项式进行计算,得到相应的字符串。

使用这样的优化后以前跑不出来的数据都是瞬间跑完。

当然除了这个问题以外,其它同学也有着不同的速度问题,下面我列举一些:

  • 在将表达式因子转为多项式时,有的同学直接在for循环中使用了表达式的toPoly(或者其它类似转换函数),导致每一次乘法都需要计算一遍内部的表达式。(除此之外指数计算也可以优化为快速幂,不过作用可能不大,毕竟指数最高才8)

  • 多项式对象的容器中没有将系数为0的项清空,导致乘法时有很多的0相乘,浪费时间,导致通不过传奇数据。

六、心得体会

1.在所有的心得体会之前,先要吐槽一下python的flet包。这是一个可以使用python实现前后端结合创建多用户应用的工具库,可以用于制作桌面程序或者网站。这一单元写评测机的时候我就使用了这一个包来作为前端。然而,不知道是不是我的操作问题,我没法将我的项目部署到服务器上,我的服务器从CenOs切到了Windows再切到了Ubuntu,都没能解决(但是应该是可以的,也懒得搞了)。

2.orzzzzzzzzzzz先膜拜一下优化仙人

3.第二次作业确实折磨了我很久,三种构造的转换虽然不复杂,但是写起来还是很难受。在实现新功能时,还是得先仔细思考,认真设计之后再动手,否则写到一半发现自己不对或者写得不好就完了(

4.这三次作业的构造我都没有用到任何继承或者是设计模式,感觉自己的代码结构不是非常完善,尤其是在可扩展性和鲁棒性上。在互测的时候我看到有的同学在代码中加入了对错误输入的反馈处理,非常佩服。

5.第一次作业写了注释,然后第二次第三次就没了,也不知道为什么(bushi

6.深拷贝和浅拷贝还是要注意一下,在这上面确实出过问题。

7.orzzzzzzzzzzz再膜拜一下优化仙人

七、未来方向

加大难度,加大难度,加大难度。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值