经过了三次作业之后,OO第一单元告一段落,作为一个蒟蒻,我初步了解了面向对象的编程思想,并将所学内容用于实践。


一、第一次作业

1.架构分析

  本次作业需要完成的任务为简单多项式导函数的求解。表达式仅支持常数项以及幂函数项的简单加减运算,并且输入保证是符合格式规范。整体要求上较为简单,但由于我对一些基础知识掌握不透彻,并且对面向对象编程的思路还理解得不够,所以整体上本次作业基本上还是面向过程,可移植性以及可扩展性很差。

  大致思路:首先将表达式化简,暴力去掉空白项,并且将连续的+、-号化简,使每项统一规范,便于正则表达式的统一。由于我没有过多注意帮助文档,我的正则表达式写得十分随意,并且采用的是对性能影响非常大的大正则。但好在本次作业整体较为简单,因此大正则没有过多影响性能。

  设计类时,我仅仅设计了一个Poly类,用于存储每一项,并且将每一项表示成cxn的形式,便于合并同类项。抽象类PolyGetter为工具类,用于获取每一项。

2.性能分析

类图如下图所示:

可以看出,这几个类之间并没有什么联系,仅仅各自完成自己的功能。

复杂度分析:

输出多项式的Poly.print()方法圈复杂度较高,v(G)达到了10,主要是本次作业我参考了上机实验的输出,因此花了较多的篇幅用于格式化输出,提高性能分(性能分和输出字符串的长度有关,复杂度高也不影响分数)。

3.评测分析

强测阶段:

  由于本次作业大家基本都进行了合并同类项,因此强测时拿到满分还是比较困难的,而我在输出的细节方面处理得不够到位(比如简单地将每项用+连接),因此扣了一些性能分,但好在没有测出bug。

互测阶段:

  我在格式化输出的时候犯了一个极其可笑的错误——当系数为-1的时候,幂的符号会输出成“^”。这一bug直接被人hack了9次,甚至一度让人以为我是抄的去年作业。好在被hack的点一次合并修复就解决了,只扣了1分,并且我算是运气比较好,hack到了同屋子内的4个bug,最后在互测时反而获得了加分。

4.反思与总结

  本次作业设计得最丑陋的一点就是将整个表达式的正则用一个字符串表示,没有进行任何拆分,导致debug时遇到困难。另外,我对程序的检查仔细程度也不够,导致出现了"^"这样的可笑失误。

  下次作业应该注重的是正则表达式字符串的拆分,并且应该增加程序的内聚性,尽量减少对其他类的调用。


二、第二次作业

1.架构分析

  本次作业在第一次作业的基础上,增加了三角函数因子(sin(x)cos(x))以及因子的乘法运算。显然本次作业的正则表达式复杂性要远高于上一次,因此使用大正则已经不可取了。同时,由于“+”、“-”号判断更复杂,且增加了判断WRONG FORMAT的要求,采用上一次的简化符号已经不可取。在这种情况下,我对所有的类都进行了重构。当然,本次作业总体上还是有点良心的,因为因子、项、表达式仍然能用固定的正则表达式表示,判断格式仍然比较方便,且保证空白字符的出现不影响格式的正确性,仍然可以暴力去空格。此外,每一项可以表示为axn1sinn2(x)cosn3(x)的形式,所以在求导、合并同类项时仍然可以归一化判断。

  在解析表达式的过程中,将表达式分解为项,再分解为因子,比上一次多了一层判断,但复杂度增加的不多。

2.性能分析

类图如下:

  

复杂度分析:

  

每个方法的复杂度比上一次作业没有明显增加,但是仍然有部分方法的复杂度较高,特别是Poly类的耦合性仍然较高,是需要改进的地方。

3.评测分析

强测阶段:

  本次作业强测是炸得最惨的一次,错了四个点,其他的点性能分也十分拉胯,主要是化简做得非常烂,仅仅只合并了三个指数都相同的情况,对实际性能分提升很小。

互测阶段:

  由于本次作业是确实写出了比较严重的bug(在循环的时候标记忘记置位),当项数比较多且符号变化时就会出错。因此被hack了多次。不过幸运的是强测数据并没有很强,错的点不是很多(我认为我的bug不配过这么多点),而且被hack的点属于同质bug,一次合并修复就OK了。也许是因为进了B屋或者C屋的原因,这次同屋的人bug都比较离谱,为了挽回一些分数,我拿他们开了不少刀,最终也是赚了一笔,当然最终的分数仍然不太好看。

4.反思与总结

  这次作业最大的教训就是没有本地充分测试,比较严重并且易于发现的bug都没有找到。我过于依赖中测的评测结果,后来发现中测等于不测。因此以后一定要在本地做充分的测试,自己编造大量的测试数据,或者尝试使用评测机生成。如果不会写评测机一定要抱紧大佬大腿,白嫖就完事了。另外,我的优化工作也做得很差,对于基本的sin2(x)+cos2(x)=1的简化都没有实现,因此性能分也比较低。这可能是跟我在做完作业后就想摸鱼有关。因此以后在做完基本的功能后,一定要想办法提高自己的性能分。


三、第三次作业

1.架构分析

  本次作业在前两次的基础上,增加了三角函数因子内可嵌套的复合函数的设定。与前两次作业相比,本次作业复杂性大大增加,其原因就在于无法用通项的形式来表示每一项,同时也无法用统一的正则表达式来解析输入的字符串(Java不支持递归正则)。但我在思考过程中发现,虽然每一项没有统一的表示方法,但在形式上有相似之处。我在编写过程中,将每一项表示为sin(f1)**m1*sin(f2)**m2*...*cos(g1)**n1*cos(g2)**n2*...*pow,其中f1,f2,g1,g2均为内层表达式,pow为第一次作业中的幂函数表达式的形式,这样就大概确定了表达式类、项类、三角函数因子类的数据结构(互相嵌套),每一项的不同三角函数因子的乘积可表示为两个三角函数因子类型的链表,pow则可用HashMap来表示,这样就可以少设计很多类。

  具体设计时,主要数据结构的类包括Poly(表达式)、Term(项)、SinTerm(正弦函数因子)、CosTerm(余弦函数因子),其中Poly类包含一个相加项Term的列表,Term类已经解释过,SinTerm、CosTerm包含一个内层Poly、指数以及标记位(判断是否为原子表达式)。在求导时,先利用乘法法则对外层函数逐项求导,然后再乘以内层函数的导数,递归求解。

  本次作业中字符串判断是一大难点。首先空白字符不保证出现在合法位置,这使得暴力去空格变得不可取。其次,不能用统一的正则表达式来判断及解析,必须层层递归下降。我在一开始设计时就误入歧途——试图将三角函数因子表示为形如sin(.*)(\\*\\*[+-]?[0-9]+)?的形式(已省略空格,其余同理),然后通过捕获组来判断内部的表达式。这样做存在难以解决的问题——正则表达式只支持贪婪匹配和非贪婪匹配,当出现形如sin((2*x+1))的因子时,采用两种方式均不能正确获取内部表达式(括号匹配不正确),这也导致我花了几乎一天的时间重构,做了很多无用功。我在重构的过程中,增加了去除冗余括号(减少递归层数)以及利用栈的原理获取括号内的子表达式的方法。由于这两个方法基本是纯面向过程的,因此我整个字符串处理工作也偏向面向过程,最终仅仅个别地方用到了正则表达式。但这未免是坏事,因为正则表达式如果写得不好很容易导致性能急剧下降。而且面向过程的方法很多时候运行速度要高于面向对象的方法(优化了内部细节)。设计好整体架构之后,判断、解析起来也就不难了。

  在输出时,我做了一些简单的优化,比如去掉了多余的正负号。但是,由于数据结构设计的问题,合并同类项变得十分困难,而且就算实现合并,对性能提升的程度仍然十分有限,因此我放弃了合并同类项。

2.性能分析

类图如下图所示:

除了主类之外共有4个结构类、两个工具类,其中生成表达式的类采用工厂模式。

由于方法过多,无法全部贴出,这里只贴出部分复杂度较高的方法:

可以看到很多方法的圈复杂度都十分难看,基本上是因为我实现这些方法是面向过程的,当然,面向对象的方法表面上降低了复杂度,但实际运行时复杂度并不低。

3.评测分析

强测阶段:

  可能是因为本次作业本身较为复杂,中测的数据很弱,强测数据也并不强,不过我还是因为一个比较明显的bug导致强测炸了一个点。

互测阶段:  

  如上文所说,我存在的bug是输出过程的漏洞,由于存在可能导致数组越界的操作而使程序RE,具体的,当输出结果为0时会抛出异常,这一点被人砍了不少刀。这一点也是因为我本地评测不到位。另外,由于程序本身算法的缺陷,在递归层数很多时程序会TLE,屋子里的一些狼人也利用这一点hack了我几次。

4.反思与总结

  本次作业最大的问题就是架构设计的问题。由于我采用惯性思维,尝试使用通项的形式表示每一项,而导致数据结构设计得过于复杂。回想起来,其实没必要将通项表示为那种形式,如果当时采用多态的方法,将幂函数、两种三角函数同时设计为因子类的子类,数据结构会简单很多,运算过程也会变简单很多,也许就不会出现TLE的情况。我对面向对象程序的结构仍然不是十分熟悉,有时不能将所学的知识充分利用。因此,在以后写程序时应该多加构思,良好的构思会减少很多工作量。


四、总结

  第一单元算是面向过程与面向对象编程的衔接过程,三次作业带来的最主要的就是思想的转变,从面向过程到面向对象,这个转变很艰难,到现在也只是摸到点头绪,必须承认我仍然是个蒟蒻。面向对象是一种思维方法。类、方法的构建与层次关系都是要不断思考不断改进的。这个单元也让我学会了很多(特别是各种API的使用),我在写代码时也发现了自己的不少问题,仍然需要不断努力,解决问题。

北航OO第一单元作业总结(1.1~1.3)的更多相关文章

  1. 2019北航OO第一单元作业总结

    一.前三次作业内容分析总结 前言 前三次作业,我提交了三次,但是有效作业只有两次,最后一次作业没能实现多项式求导的基本功能因此无疾而终,反思留给后文再续,首先我介绍一下这三次作业,三次作业围绕着多项式 ...

  2. 北航OO第一单元作业总结(Retake)

    前言:当我写这篇博客的时候,我的心情是复杂的,因为这实际上是我第二次写这篇博客--我今年重修的这门课.我对去年的成绩心有不甘--在激烈的竞争下,我虽然尽可能完成了所有作业(仅一次作业未通过弱测),但爆 ...

  3. 【OO学习】OO第一单元作业总结

    OO第一单元作业总结 在第一单元作业中,我们只做了一件事情:求导,对多项式求导,对带三角函数的表达式求导,对有括号嵌套的表达式求导.作业难度依次递增,让我们熟悉面向对象编程方法,开始从面向过程向面向对 ...

  4. 【作业1.0】OO第一单元作业总结

    OO第一单元作业已全部完成,为了使这一单元的作业能够收获更多一点,我回忆起我曾经在计算机组成课设中,经常我们会写一些实验报告,经常以此对实验内容反思总结.在我们开始下一单元的作业之前,我在此对OO第一 ...

  5. OO第一单元作业总结——表达式求导

    OO第一单元作业总结 第一次作业 基于度量分析代码结构 基本算法 第一次作业是简单多项式导函数求解,不需要对输入数据的合法性进行判定, 基本思想是用 (coeff, expo)表示二元组 coeff* ...

  6. OO第一单元作业总结

    oo第一单元的作业是对多项式的求导.下面就是对三次作业分别进行分析. 第一次作业 分析 第一次作业相对来讲比较简单,甚至不用面向对象的思想都能十分轻松的完成(实际上自己就没有使用),包含的内容只有常数 ...

  7. 2020北航OO第一单元总结

    前言 学习面向对象这门课程的后的第一单元作业,主线是多项式求导,三次作业层层推进,由单一的幂函数求导,到幂函数和三角函数的复合求导,最后再到两种函数的嵌套求导,由两个类到重构后的十几个类,我逐渐对面向 ...

  8. 2019年北航OO第一单元(表达式求导任务)总结

    2019面向对象课设第一单元总结 一.三次作业总结 1. 第一次作业 1.1 需求分析 第一次作业的需求是完成简单多项式导函数的求解,表达式中每一项均为简单的常数乘以幂函数形式,优化目标为最短输出.为 ...

  9. OO第一单元作业小结

    前言 第一单元的主题是表达式求导,第一次作业是只带有常数和幂函数的求导,第二次作业加入了正余弦函数,第三次作业又加入了表达式嵌套,难度逐渐提升.总体来说前两次作业还易于应对,而第三次作业做得相对有些艰 ...

随机推荐

  1. 2020 web developer roadmap

    2020 web developer roadmap https://github.com/kamranahmedse/developer-roadmap https://roadmap.sh/ ht ...

  2. Baccarat中挖矿、兑换和做市的三角关系是什么?

    NGK在这波DeFi潮中,推出了Baccarat,为用户带来了流动性挖矿收益,今天笔者就讲一讲Baccarat中挖矿.兑换和做市的关系. 兑换和做市是什么关系呢?众所周知,换币者,是用一种货币去换另一 ...

  3. 2018-1-6-IDEA快速代码生成

    2018-1-6-IDEA快速代码生成 Java 自动生成 Intellij IDEA 利用IDEA编辑器的Live Templates可以实现自定义方法.属性.注释等,下面是我自己的常用模板. 属性 ...

  4. C++入门教程:大白话讲解,新手基础篇⭐⭐⭐(附源码及详解、视频课程资料推荐)

    目录 C++教程 前言 视频教程 文字教程 集成开发环境(IDE) 编译器 工作原理 学习指南 入门书籍 进阶书籍 算法.竞赛书籍 教程 标准构建 程序解释 第一个C++程序--"hello ...

  5. 微信小程序:数组拼接

    一开始用concat进行拼接,总是不行,代码如下: handleItemChange(e){ console.log(e) var itemList = e.detail.value itemList ...

  6. 微信小程序开发小技巧:

    小技巧:输入view.tabs_content就可以生成下面的代码. 输入p10,就可以得到: 输入jc:c得到:文字水平对齐 输入d:f得到: 输入ai:c得到: 输入bb得到: currentCo ...

  7. Go中的if-else判断

    目录 go中的if-else判断 一.语法 go中的if-else判断 一.语法 if 条件 { //符合上面条件的执行 } else if 条件{ //符合上面条件的执行 } else { // 不 ...

  8. wxWidgets源码分析(4) - 消息处理过程

    目录 消息处理过程 消息如何到达wxWidgets Win32消息与wxWidgets消息的转换 菜单消息处理 消息处理链(基于wxEvtHandler) 消息处理链(基于wxWindow) 总结 消 ...

  9. SpringMVC异步处理的 5 种方式

    作者:丁仪 来源:https://chengxuzhixin.com/blog/post/SpringMVC-yi-bu-chu-li-de-5-zhong-fang-shi.html 前段时间研究了 ...

  10. PTA甲级—数学

    1.简单数学 1008 Elevator (20分) 模拟题 #include <cstdio> #include <cstring> #include <string& ...