BUAA_OO_2020_Unit1_总结

2020年春季学期第四周,OO第一单元落下帷幕,几多欢喜几多愁,现做如下总结(按每次作业的递进顺序)

一、第一次作业(基础的幂函数求导)

  • 基于度量的程序结构分析

  第一次作业是较为简单的幂函数的求导,由于没有错误格式的数据出现,我们处理源字符串的方式也变得尤为简单。存储表达式的数据结构也可简化为已有的数据结构。本人初采用的Hashmap来简化输入数据的化简检索步骤,后由于考虑优化时的系数排序情况,又将数据结构换成了Treemap,在此过程中多体会到了常用数据结构,如ArrayList,HashMap,TreeMap之间的不同优缺点。

  而对于面向对象思想的训练,本人初步仅使用了项,以及表达式的类来创建表达式对象,而对于表达式的求导部分则单独放在了一个工厂类之中用来表示对表达式的加工。代码分析如下

  对于方法中的分析,表达式的构建以及输出的圈复杂度较高,具体原因可能在于输出的简化判断过程,而这个复杂度随着作业的迭代会逐渐提升,如何降低其复杂度,符合“高内聚,低耦合”的程序特性,也是本人下一步需要提高思考的地方。

  • 评测

  在第一单元中强测中未发现bug,在互测之中由于构造些特殊条件,如“0”,负数次幂,导致成功hack到了同room的同学,这些特殊条件也是我测试自己代码时留下的测试用例。

二、第二次作业(引入三角函数及因子的乘积)

  第二次作业也是最让我心碎的一次心路历程,功能性实现本身较为简单。而本人用了极大精力优化输出的同时,却在关键位置留下致命bug,导致强测结果直接爆炸,无力回天。真可谓:为山九仞,功亏一篑。这也提醒本人在优化时更要做好全方位的测试。

  • 基于度量的程序结构分析

  第二次作业引入了三角函数sin与cos,并且支持因子之间的乘积,而且引入了简单的不包含空白字符的错误输入。这样的条件下需要我们简单的改进我们的策略,对于空白字符我们仍然可以在表达式中进行处理,而错误输入由于表达式本身不存在多于的递归输入(相比于第三次作业),所以我大胆采用了全部表达式的正则构造,在字符串输入初期即判断其是否合理的情况。简化了判断的流程。

  而在表达式的构造方面,虽然多引入了形式,但最终的每一项仍然可以表达成a*x^b*sin(x)^c*cos(x)^d的形式,其中abcd为四个系数,只要将四个系数作为属性放入Term类中,并以bcd为属性放入Keys中作为HashMap整体的Key索引,HashMap就仍然可以作为我们表达式构建的数据结构。再重新改造一下我们的输出以及求导方法,第二次作业的迭代工作就完成了,具体的代码分析如下:

UML图

  相较于第一次作业,第二次作业的圈复杂度也体现在了化简之中(除第一次作业的化简策略)。我采用的化简策略是扫描任意两项,观察其是否符合:

    • x的指数相等
    • sin,cos指数分别相差2/sin差2/cos差2

  本人的大量计算以及分析得出这种化简策略的优化绝大多数情况都为正向,强测通过的样例获得的性能分也较为理想,但本人在遍历项的过程中,产生的优化,并未对已优化的项处理,导致下一次遍历仍会触及,这样致命的bug在提交之后才猛然发现,却已为时已晚。不禁对自己强测可怜的分数扼腕叹息。

  • 评测

  本人毫无意外的被分进了C屋,也发现了很多同屋人的bug,战况十分惨烈,但同屋的人并未hack出我的问题,(自己还是有几分小侥幸),构造出的测试样例包含简单的多符号处理,以及基本的常数情况等等,本身不是很具有代表性再次不赘述。

三、第三次作业(引入嵌套)

  造成第三次作业难度激增的一个“罪魁祸首”就是嵌套规则,但我们仍有消除恐惧的办法。在构建表达式树的过程中本人深深体会到了大一下数据结构的重要性。

  在与同学深切的讨论(其实是向大佬取经)之后,我沿袭其构造思想。将整体思路表述如下:

  1)对于整体字符串构造正则表达式,对于嵌套内容利用“\(.*\)"进行构造,目的为仅仅检查最外层的逻辑,符号是否正确。而对于其中具体的项、因子,我会在构造之中进行同步的检查。若符合则构造,不符合则报错。

  2)在构造过程中,先将项之间的符号处理成一个,再扫描表达式,以"+-" > "*" > "嵌套”的优先级进行构造,其中嵌套包含的“+-”号需要特殊考虑。在扫描的过程中按照不同的优先级,构造分支节点类型,再将左子树,右子树构造的字符串提取出来,递归进行下一层树的构建。

  3)构造好之后对树进行中序遍历,访问叶子节点就输出其求导结果,访问分支节点就读取其符号类型,进行不同的求导规则递归调用,如“*”,就递归调用“左子树求导 * 右子树输出 + 左子树输出 * 右子树求导”,其中的括号问题,则针对优先级进行填充,若父节点优先级较高,则在自述输出时为其填充括号。

  在化简的思路上,由于在构造过程中耗费大量心血,化简我仅仅考虑了符号的减少输出以及项中包含0,包含常数时求导结果的化简,取到了一些成果,但仍有较大的优化空间。

  代码分析如下:

UML图

  由于采用了递归调用的方式,Poly类的输出,求导以及其连带了某些函数的求导,输出都出现了复杂度较高的情况,但这种思路较前两周有了更大的提升,本身也更符合面向对象的思维方式。对于函数组合的方式,我并未将其分成单独的类,这有些符合面向过程的思维方式,可以得到进一步的完善,本身对于降低耦合度也会有很大的帮助。

  • 评测

  在第三次作业之中,本人也遇到了一个差点致命的错误,就是指数的存储形式,指导书所言不大于50,这就诱导了我用Long储存,然而遇到超Long的数会直接报错,这一点超出了我的测试范围,导致我在中测最后一个点卡了许久,几近绝望。后经高人指导,幡然醒悟。才苟进了强测。在强测之中遇到了项中符号的错误格式无法判断的情况,我为其单独书写了一个正则判断错误,这本身也体现出了我构造测试用例一个不全面的表现。

  在互测之中,我将之前测试的用例以及一些自动生成的数据进行测试,发现了一些同学的bug,主要集中在多符号的处理,以及嵌套内部内容处理的问题上,这些都是我在写自己程序之中最头疼也是测试最久的地方。

四、程序bug分析

  具体的bug分析在前三个部分都有提到,我在此进行一下总结:

  • 属性存储形式不对导致溢出的bug
  • 多符号处理产生的漏判错误格式的bug
  • 优化过程中循环调用产生的bug

  后两个bug直接极大影响了我的测试成绩,也是我在测试自己程序忽视的地方。

五、互测hack策略

  互测hack是一个斗智斗勇的环节,也是OO课程设计的一大亮点。互测让我们既做了开发者又做了用户(对用户透明)。对于hack我自己在第一单元采用的策略有几个:

  • 先采用简单的测试用例,采用debug的形式对程序运行逻辑进行分析,再构造一些极端测试用例,观察是否有程序检测的覆盖
  • 采用自动生成的测试用例,进行大范围的盲狙,发现bug,再逐步缩小范围进行bug定位,最终定位bug错误原因。
  • 用脚本进行普遍测试,发现错误

  诸多策略结合使用,可以提升自己的hack效率,避免盲开枪浪费机会也浪费时间的现象。

六、对象创建模式

  这三次作业本身都是应用工厂模式创建对象的一个良好的机会,但由于输入条件的简单,我的表达式工厂仅用来协助创造了求导,以及输出的方法。而本身表达式的创建我使用了表达式对象自身的构造方法,这种方法也直接导致了构造方法的复杂度,耦合度较高。将构造方法移植到工厂中进行构建我认为更符合创建模式,而且可以一定程度上解耦。

  在第三次作业之中我引入了抽象类表示因子,引入了抽象方法求导与因子输出,再将多种因子继承,实现方法。构造表达式时利用多态进行对象的管理。这种实践较为成功。

七、心得体会

  第一单元的三次作业难度逐步提升,本人在第三次作业中耗费精力甚多,可能有如下原因:

  • 对于树的数据结构实现不熟练,大一下知识基础储备不扎实,需补齐
  • 思维不具有化整为零的特点,思考许多种情况导致思维一团乱麻,无从下手
  • 思维不连贯,导致构造好功能之后在括号处理方面遇到了好多bug,究其原因就是括号处理初期思想错误。

  第一单元也在继承、多态、接口、对象创建模式等方面对我们进行了强化练习,两次实验三次作业效果都很好。也让我们体会到了这门课有多么充实,多么硬核。互测的圣杯之战是多么惨烈。要想活下去,就继续战斗吧!勇士们。

  总结:多看讨论区,多构造样例,多向大佬请教:)

BUAA_OO_2020_Unit1_总结博客的更多相关文章

  1. Android请求网络共通类——Hi_博客 Android App 开发笔记

    今天 ,来分享一下 ,一个博客App的开发过程,以前也没开发过这种类型App 的经验,求大神们轻点喷. 首先我们要创建一个Andriod 项目 因为要从网络请求数据所以我们先来一个请求网络的共通类. ...

  2. 一步步开发自己的博客 .NET版(11、Web.config文件的读取和修改)

    Web.config的读取 对于Web.config的读取大家都很属性了.平时我们用得比较多的就是appSettings节点下配置.如: 我们对应的代码是: = ConfigurationManage ...

  3. 一步步开发自己的博客 .NET版(10、前端对话框和消息框的实现)

    关于前端对话框.消息框的优秀插件多不胜数.造轮子是为了更好的使用轮子,并不是说自己造的轮子肯定好.所以,这个博客系统基本上都是自己实现的,包括日志记录.响应式布局.评论功能等等一些本可以使用插件的.好 ...

  4. 【原】Github+Hexo+NextT搭建个人博客

    摘要 GitHub 是一个开源项目的托管网站,相信很多人都听过.在上面有很多高质量的项目代码,我们也可以把自己的项目代码托管到GitHub,与朋友们共享交流.GitHub Pages 是Github为 ...

  5. 我为什么要写LeetCode的博客?

    # 增强学习成果 有一个研究成果,在学习中传授他人知识和讨论是最高效的做法,而看书则是最低效的做法(具体研究成果没找到地址).我写LeetCode博客主要目的是增强学习成果.当然,我也想出名,然而不知 ...

  6. 博客使用BOS上传图片

    1.博客平台的选定 从大学开始做个人主页算起,最开始是使用html,CSSS写简单的页面,后面大学毕业之后接触到了WordPress,就开始用WordPress搭建网站.现在还维护着一个农村网站.ht ...

  7. 在jekyll模板博客中添加网易云模块

    最近使用GitHub Pages + Jekyll 搭建了个人博客,作为一名重度音乐患者,博客里面可以不配图,但是不能不配音乐啊. 遂在博客里面引入了网易云模块,这里要感谢网易云的分享机制,对开发者非 ...

  8. iOS controller解耦探究实现——第一次写博客

    大学时曾经做过android的开发,目前的工作是iOS的开发.之前自己记录东西都是通过自己比较喜欢的笔记类的应用记录下了.直到前段时一个哥们拉着我注册了一个博客.现在终于想明白了,博客这个东西受众会稍 ...

  9. 中文 iOS/Mac 开发博客列表

    中文 iOS/Mac 开发博客列表 博客地址 RSS地址 OneV's Den http://onevcat.com/atom.xml 一只魔法师的工坊 http://blog.ibireme.com ...

随机推荐

  1. Angular SPA基于Ocelot API网关与IdentityServer4的身份认证与授权(一)

    好吧,这个题目我也想了很久,不知道如何用最简单的几个字来概括这篇文章,原本打算取名<Angular单页面应用基于Ocelot API网关与IdentityServer4+ASP.NET Iden ...

  2. JAVA自定义数据类型用法

    一,自定义数据类型的概念:    我们就拿一部手机进行分析,它能用来做什么呢?它可以打电话,上网,聊微信等,这些就是 手机所提供的功能,也就是方法:手机也有它的特征,如颜色.尺寸大小.品牌型号等,这些 ...

  3. C#中操作JSON

    引入支持JSON操作的库,比如LitJSON: 引入之后就可以解析JSON了. 写一个JSON文本 读取这个JSON文本: 解析JSON数据最佳实践--使用泛型,将泛型类型指定成自己定义的类型,直接获 ...

  4. 由一次安全扫描引发的思考:如何保障 API 接口的安全性?

    引言 前段时间,公司对运行的系统进行了一次安全扫描,使用的工具是 IBM 公司提供的 AppScan . 这个正所谓不扫不要紧,一扫吓一跳,结果就扫出来这么个问题. 我们的一个年老失修的内部系统,在登 ...

  5. 使用websocket开发智能聊天机器人

    前面我们学习了异步web框架(sanic)和http异步调用库httpx,今天我们学习websocket技术. websocket简介 我们知道HTTP协议是:请求->响应,如果没有响应就一直等 ...

  6. python3.7 64bit安装pygame1.9.3

    https://blog.csdn.net/xiaolixi199311/article/details/79209506/

  7. [JavaWeb基础] 014.Struts2 标签库学习

    在Struts1和Struts2中都有很多很方便使用的标签库,使用它可以让我们的页面代码更加的简洁,易懂,规范.标签的形式就跟html的标签形式一样.上面的篇章中我们也讲解了自定义标签那么在如何使用标 ...

  8. undefined和nul

  9. Entity FrameWork 实现分页

    SQl语句进行分页 SQL语句进行分页主要是应用Entity FrameWork的SqlQuery()传入SQL语句进行查询时分页. 效果展示. 页面代码展示,显示是用Repeater控件进行动态显示 ...

  10. Java实现 LeetCode 518 零钱兑换 II

    518. 零钱兑换 II 给定不同面额的硬币和一个总金额.写出函数来计算可以凑成总金额的硬币组合数.假设每一种面额的硬币有无限个. 示例 1: 输入: amount = 5, coins = [1, ...