第一次作业

第一次作业需要完成的任务为简单多项式导函数的求解。

思路

因为仅仅是简单多项式的求导,所以求导本身没有什么可说的,直接套用幂函数的求导公式就行了,主要的精力是花在了正则表达式上。这里推荐两个网站:

https://github.com/ziishaned/learn-regex

https://regex101.com

前者可以用来学习正则表达式的语法,后者则提供实时的正则表达式匹配,方便进行调试和验证。尤其是后者,能大幅提高编写正则表达式的效率和正确性,省去了每次都得在IDEA里运行一遍的麻烦。

用正则时有一点需要注意,那就是大正则是不可取的。我一开始就是企图用一大串正则匹配整个输入,结果当时是爆栈了。合理的做法应当是每次只find()一个Term,以及通过Term与Term之间的连接关系判断合法性。

在数据结构方面,我一开始用的是ArrayList,但在后来优化的时候发现合并非常麻烦,于是果断放弃,学习并采用了HashMap。通过将指数作为Key,可以快速地找到指数相同的项,以实现合并同类项的目的。

程序结构分析

由于刚接触Java语言,也不太懂什么是面向对象思想,所以程序整体来说还是比较C type的。也可能是由于本次作业比较简单,所以也并没有用到继承、接口之类的东西。从类图中可以看到,一共也就两个类,其中PolyDiff完成主函数、预处理、合法性判断等任务,而Term则实例化出多项式中的每一项,保存系数和指数,并提供diff()求导方法。

度量分析

可以看出个别方法复杂度过高,这很不OO。下次应当多注意抽象以及代码重用,避免一个方法或者类的过于臃肿。

关于BUG

公测未被查出bug。在互测阶段,我第一个发现的bug是自己的bug,其原因在于,我判断合法性的做法是将匹配了的每一项用"#"替换掉,最后看除了" "、" \t"、"#"之外是否没有其他的字符。然而,我忽略了输入一开始就含有"#"的可能,但这种可能性非常小,以至于我认为只要不仔细阅读我的代码,基本上是不可能歪打正着的。遗憾的是,最终还是有一位十分认真的同学,(我猜)在一行一行通读了我的整个代码后,居然还真的发现了这个bug……我是服气的,真的太强了orz

至于我查别人的bug,都是用的我写作业时自测发现了bug的样例,因为我相信这样的样例会具有一定的杀伤力和普适性。事实证明,我的确能用这种方法测出很多别人的bug,于是也就没有再结合他人的代码设计结构来设计更多的测试样例。

第二次作业

第二次作业需要完成的任务为包含简单幂函数和简单正余弦函数的导函数的求解。

思路

第二次作业新引入了正余弦函数,乍看复杂了许多,但其实还是可以用套公式的办法死做,然而代价就是毫无扩展性可言。

对于每一项及其导函数,都可以化为幂函数和正余弦函数的幂次的乘积这种标准形式,那么Term就相应拥有了系数、幂函数及正余弦函数的指数这四个属性。除了正则表达式匹配和求导规则有一些变化,其余与第一次作业并无太大区别。

值得注意的是,这次HashMap的Key我采用的是将幂函数及正余弦函数的指数拼接成一个字符串,并在相邻指数之间用"|"分隔。如此一来,便可省去重写equals()和hashcode()的麻烦,然后像第一次作业一样合并同类项。

程序结构分析

程序结构大体类似于第一次作业。

度量分析

合法性判断的方法还是有些冗长了,可能是因为其中包含了一些对输入进行预处理的操作,可以考虑将这部分单独抽离出来。

关于BUG

在吸取了上一次作业的教训后,我舍弃了替换捕获组方法,而是根据本次匹配起点是否为上一次匹配的终点,以及最后一次匹配的终点是否为字符串的末尾,来判断输入的合法性。最终在公测和互测中都未发现bug。

发现别人程序的bug依然采用上一次作业的方法,果然又查出了不少bug,大多是对于非法的输入没有输出WRONG FORMAT!

第三次作业

第三次作业需要完成的任务为包含简单幂函数和简单正余弦函数的导函数的求解(支持因子嵌套在三角函数因子中)。

思路

正如之前所说的,套公式的做法是无法解决任意层嵌套的问题的,因此整个程序架构必须重构。在这里我采用的是递归下降的方法,规定好每种函数、组合的求导法则,将嵌套的内容看做一个整体,留给下一层递归处理,每次只判断当前层的合法性并进行相应的求导。

在优化方面,仅仅是剔除了冗余的0、1、括号、正负号等等,在同类项合并和恒等变换方面未能进行更多的处理,其原因和求导方法的返回值有关。由于我在一开始设计的时候就直接把每个因子的求导结果当作字符串保存,所以整个表达式求导的过程就相当于是字符串按一定规则转化和拼接的过程。这样做的好处在于简答、直观、不易出错,但弊端也很明显,那就是很难做进一步优化,因为对字符串中的内容是无法进行插入、删除、替换、排序或合并等操作的,除非像读取输入那样再一次对字符串进行分析。由于时间有限,我没有那样做。其实更好的方法是将求导的结果也作为某一个类的实例,方便对其做进一步的处理。

程序结构分析

如图所示,本次作业我用到了面向对象中的继承,有必要这样做的原因有三:

  1. 每个子类都需要toString()方法,以返回该项因子自身的字符串。由于这个方法对于每种因子都一样,所以应该在父类中统一实现。
  2. 每个子类都需要实现各自的diff()方法,因为每种函数或组合都有自己的求导规则。
  3. 每个子类都继承于Factor类使得不同类型的因子可以放在一个ArrayList中一起处理。

至于Term,它并不是因子,只是Expr的组成部分,所以单独成为一类。

通过继承这种面向对象的思维方式,我们程序的结构更加清晰,功能更加强大,最重要的是,拥有了可扩展性。

度量分析

果然越复杂的程序,要做到均衡控制每个方法的复杂度就越难。主要的问题依然出在输入分析、预处理以及合法性判断上,尽管这次我将他们分离了开来。至于有没有必要以及如何进一步拆解,还有待研究。

关于BUG

本次作业依然没有被查出任何bug。

在查别人的bug方面,为了解放劳动力,这次我选择写脚本进行批量测试。我用到了Python中一个强大的第三方包——SymPy,可以进行复杂表达式的求导运算以及判断两式是否等价,这也是我的"简化版评测机"的主要原理,即将Java程序的输出与SymPy的输出进行比对。显然,该评测机无法对非法输入给出评判。而测试用例本身依然是我自测时手动构造的测试集,按行读取便可进行批量测试,威力极大,效率奇高。

总结与建议

第一单元总体还是比较入门的,重点在于熟悉Java语法特性、建立面向对象思维,为日后的多线程编程打好基础。

对于我个人而已,学习了Java正则表达式、BigInteger类、HashMap、重写与重载、继承与接口等等技术,并且慢慢开始理解了层次化架构和面向对象技术的优越性。总体感觉Java还是比C/C++要方便的多,基本上只要是你能想到的功能,总有类或者第三方包能为你提供解决方案。而这就需要我们有查找资料自学的能力,无论是看技术博客还是阅读官方文档,再加上自己多动手实践,相信很快就能掌握一项新的技术,并在作业中发挥其功能。

此外,通过Checkstyle对代码风格进行规范也是比较有效的措施,基本上不会再写出会令人抓狂的代码了。但是其中每行最多80个字符的限制我实在觉得不太合理,尤其是涉及正则表达式的时候,往往是硬生生地把一句逻辑连贯的代码拆成多行。个人认为在阅读代码时,莫名其妙的换行比一行稍长的代码体验更糟。建议将每行的字符数上限改为100~120。

对于面向对象的理解可能还是只是停留在表层,甚至会有一些误解,这就需要进一步的学习和练习,在一次次实践中总结经验与教训。希望以后能写出更加OO的程序。

BUAA-OO-2019 第一单元总结的更多相关文章

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

    目录 总 架构 Controller​ Model​ 输入处理 代码静态分析 行数 方法复杂度 UML​ 类图 优点 缺点 坑 输入 非法的空白字符 输入的简并处理 运算 浅拷贝 可变类型与不可变类型 ...

  2. BUAA OO 2019 第二单元作业总结

    目录 总 架构 controller model view 优化算法 Look 算法 多种算法取优 预测未来 多线程 第五次作业 第六次作业 第七次作业 代码静态分析 UML 类图 类复杂度 类总代码 ...

  3. OO面向对象第一单元总结

    OO面向对象第一单元总结(表达式求导) 写在前面: 魔鬼课程oo第一单元终于结束,当终究要落笔总结,竟不知从何写起…… 回首再去看第一次的作业,你会满足于那时的幸福,或许,这就是成长吧! 千言万语,一 ...

  4. BUAA OO 2019 第四单元作业总结

    目录 第四单元总结 总 UML UML 类图 UML 时序图 UML 状态图 架构设计 第十三次作业 第十四次作业 课程总结 历次作业总结 架构设计 面向对象方法理解 测试方法理解与实践 改进建议 尽 ...

  5. 北航oo作业第一单元小结

    前言 在经过了三次艰辛的oo作业后,oo课程的第一单元告一段落,这一单元,我作为一个oo小白,开始了解oo的编程思想,也有了自己的一点心得体会.把笔粗成字,不当之处,还请各位大佬多多指教. 一.分析程 ...

  6. OO作业第一单元总结

    一.第一单元作业回顾 ​ 系列一作业分为三周进行,都是表达式求导,难度渐进. ​ 第一次实现的是简单幂函数的求导,第二次加入了sin和cos两种三角函数,第三次实现了三角函数内的嵌套以及引入了表达式因 ...

  7. BUAA OO 2019 第三单元作业总结

    目录 总 JML规格化设计 理论基础 工具链 规格验证 验证代码 代码静态检查 自动生成测试样例 生成结果 错误分析 作业设计 第九次作业 架构 代码实现 第十次作业 架构 代码实现 第十一次作业 架 ...

  8. UML结构与解析——BUAA OO第四单元作业总结

    UML与解析架构 UML是什么 统一建模语言(英语:Unified Modeling Language,缩写 UML)是非专利的第三代建模和规约语言.UML是一种开放的方法,用于说明.可视化.构建和编 ...

  9. OO第四单元总结暨期末总结

    OO第四单元总结暨期末总结 目录 OO第四单元总结暨期末总结 第四单元三次作业架构与迭代 整体感受 HW1 HW2 HW3 四个单元架构设计与方法演进 Unit1 Unit2 Unit3 Unit4 ...

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

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

随机推荐

  1. 从架构开始谈dubbo(二)-----zookeeper安装和dubbo文档查阅

    一.Zookeeper下载与安装 1.官网地址下载 https://zookeeper.apache.org/ 2.找到图中英文位置(英文不好,安图操作就好了,计算机很多东西如果你没法很好的记忆,就画 ...

  2. mysql小结(了解)

    Mysql总结 1.数据库的概念 """ 数据库:库(文件夹).表(表结构文件.表数据文件(索引结构)).字段(数据的描述).记录(数据的本体) 分类:效率问题(内存大于 ...

  3. [解决方案]IIS常见问题集锦

    内容 地址 更新时间 IIS7如何实现访问HTTP跳转到HTTPS访问 https://www.cnblogs.com/xiefengdaxia123/p/8542737.html 2019-10-1 ...

  4. mongodb数据库操作 python+命令行

      一.python操作 from bson.objectid import ObjectId import pymongo client1 = pymongo.MongoClient(host=) ...

  5. Laravel集成Swoole教程

    1.准备工作 安装 Laravel laravel new laravel-swoole     本人使用 valet 进行开发,可以使用 laravel-swoole.test     进行访问 2 ...

  6. Zhe Second Language——

    You got things to do. Place to go. People to see. Futures to make. 我们还有事要做,有地儿要去,有人要见,有梦要实现. Remembe ...

  7. 【剑指offer】构建乘积数组

    题目描述 给定一个数组A[0,1,...,n-1],请构建一个数组B[0,1,...,n-1],其中B中的元素B[i]=A[0]*A[1]*...*A[i-1]*A[i+1]*...*A[n-1].不 ...

  8. [转帖]算法精解:DAG有向无环图

    算法精解:DAG有向无环图 https://www.cnblogs.com/Evsward/p/dag.html DAG是公认的下一代区块链的标志.本文从算法基础去研究分析DAG算法,以及它是如何运用 ...

  9. DataTable 删除行 UpdateTable 方法

    .不要使用DataTable.Rows.Remove(row) 而要使用 DataTable.Rows[i].Delete() .DataTable.Rows.Remove(row)相当于DataTa ...

  10. 拦截器配置类使用继承写法导致jackson的全局配置失效

    问题描述 项目中需要一个拦截器用于拦截请求,在没有请求中生成requestId.然后写了一个配置类,这个类继承了 WebMvcConfigurationSupport类,重写了addIntercept ...