三次作业,三次成长

第一次作业——幂函数求导总结

作业思路和心得

第一次作业的要求只有x的指数这样的幂函数加减组成表达式,对表达式进行求导,而且没有格式错误的检查,所以难度感觉还不是很高。不过由于我寒假的preview作业还有两个task没有做完,所以我感觉自己对语法和字符串处理等方面还不是很熟练。因此,虽然看起来第一次作业难度不高,但是我仍然十分认真地对待它,把它当作巩固自己基础的一次机会(之后的作业就没机会巩固基础了

进入正题,第一次作业由于只有一种幂函数,所以我的思路也比较简单:直接用TreeMap存储x的系数和指数,其中以指数作为Key以便于合并同类项。求导规则也很简单,只需将TreeMap里的每个元素取出来系数乘以指数输出为系数,指数-1作为新指数就完成了求导过程。

第一次作业让我调试了很久的地方是用正则表达式读入输入并进行分割,由于我对正则表达式掌握不熟练,期间查阅了众多资料和助教发的教程,最终在不断的摸索和尝试下,我写出了那个分割输入的正则表达式,写出正则后,后面的处理就显得简单很多了。第一次作业让我对正则的了解更深入一步。

程序结构分析

  • UML分析

    第一次作业由于对面向对象思想理解不够,同时作业结构较简单,所以我在第一次作业只有一个Main类,有131行,类图也只有一个类,就不上图了。(以后要是再这么写就要次次重构了呢!

  • 复杂度分析



    从分析表中可以看出,我的第一次作业中的getInf方法的设计复杂度和圈复杂度都较高,回归代码本人确实发现这个方法中if-else的结构嵌套较多且逻辑较复杂,同时由于它是第一次作业提取因子的主要方法,所以其被其他方法调用的次数也较多,导致其和其他方法的耦合度也较高,设计复杂度过高,导致其扩展性和复用性较差。

hack与被hack

第一次作业给了我惨痛的教训。我在强测中只得了18分,为什么呢?原因就在于我在优化过程中对正数的输出我误以为只会在开头,于是把+省略了(大概脑子一抽,捂脸.jpg),导致了我在强测中大量的输出格式错误,也就导致了我没有机会进入互测,第一次作业中也就没有得到什么hack别人的经验。

第二次作业——幂函数加三角函数求导

作业思路和心得

第二次作业除了幂函数还外加了三角函数,不过好在三角函数内部只能是x,这样所有输入的形式也最终可以化为三种:xa,sin(x)b,cos(x)^c。那么这样的话,我依旧可以沿用第一次作业的总体思路,即用TreeMap进行输入因子的存储,只不过这次的Key要新建一个类来存储三个因子各自的指数,求导方法的话也只需分成六类即可(三种因子随意组合——6种)。这次唯一与上一次不同的是多了WF判断。那我的思路是,既然错误那么多,找也找不全,不如构造正确的表达式的正则表达式,输入的能匹配,那就OK,匹配不上那就肯定是WF。这种思路避免了WF的漏判。

但由于这次输入复杂了一些,同时还要构造正确的正则表达式来判断格式,让我在第一次作业中学习到的正则表达式知识又捉襟见肘了。于是我在第二次作业期间,又花了一部分时间去学习更高级的正则表达式用法,最终第二次作业也是用正则表达式的形式来读取输入,判断格式,效果还不错。做完第二次作业,我感觉自己对正则表达式又有了更深一层的理解。第一次作业结束感觉自己正则表达式掌握的不错了,第二次作业结束让我感觉自己对正则表达式还有很多需要学习的地方,因为越是深入越是发现正则表达式的高级用法还有很多我所不知道的。我要在今后的学习中进一步深入了解正则表达式的用法和原理。

程序结构分析

  • UML分析



    第二次作业中我是在第一次作业的基础上添加了三个类用来存储三个因子作为一个整体信息单位的信息。看起来有了一点OO的意味,但是写完三次作业回头来看,本人第二次作业使用的类并不是为了构建OO的思想架构而是在迫不得已的情况下为了沿袭第一次作业的TreeMap思想,不得已加入几个存储信息的类。那些类的作用实质上仅仅封装了数据,类似于C语言的结构体,实际上并没有什么架构上的改变,这是我需要在今后的设计中进行改进的。类的作用不应仅仅局限于封装数据,而是发挥它们真正强大的功能。

  • 复杂度分析





    第二次作业的整体结构较第一次作业明显复杂了许多,所以整体复杂度也有所上升。图中所示我的main方法基本复杂度是最高的,其他复杂度也很高,原因在于我给TreeMap的排序接口comparator进行了重写,因为Key是我自己定义的类。这部分重写我需要对自定义类里的三个指数依次进行比较判断,导致if-else结构很多,复杂度提升。之后查资料我发现这个方法重写也可以在自定义类内进行,这样可以大大降低main方法的复杂度,让main方法看起来更简洁。

    除了main方法,还有几个方法复杂度较高。Stringprocess、display、judgekind等方法复杂度都较高,这就是我在UML分析里所说的,我在第二次作业中新建的几个类并没有帮助我降低整体结构的复杂度也没有降低耦合度,仅仅是封装了数据,所以复杂度高的方法内部仍然有许多if-else判断和过程式的残留痕迹。这些都需要我在以后的学习中尽力克服,养成良好的习惯和思想。

hack与被hack

我在第二次作业中终于第一次体会了互测的快(刺)乐(激)。我第一次有机会看到别人的代码,我抱着学习的心态,把每一份代码都下载下来看一看。但是我发现除了几份架构清晰、逻辑至少能看明白的代码外,其他的真的很难理解,也不知道他想干什么。所以,我决定不用完全看懂代码,直接上测试数据。

测试方面,我其实不习惯于使用自己搭建的评测机,因为我觉得那样覆盖性不好,而且重复数据较多,效率不高。我更喜欢自己根据指导书,自己手动构造一些特殊易错数据进行自己的测试和互测的用例。实践证明,互测中我使用的都是我自己在写代码的时候自己积累下来测试自己程序的用例,效果还可以,至少每组数据都至少能hack到一个房间内成员。

第二次作业我自己程序的bug又是出在了化简的过程,又是在某一种情况下少输出了一个+(再一再二,不能……。

小提示(给自己以后准备的

JAVA语言中类是引用类型的,所以当类作为参数传递时,对参数的操作也会对外部的类变量产生改变。所以在相对类的部分进行操作并产生新的类时,一定要进行clone或是copy。在本次作业中我就使用了这种方法来进行操作,先来看代码:

```

public static Inf CopyInf(Inf a) {

    Inf newInf = new Inf(null, null);

    if (a.getKey().getXindex() != null) {

        newInf.setKeyX(new BigInteger(a.getKey().getXindex().toString()));

    }

    if (a.getKey().getSinindex() != null) {

        newInf.setKeySin(new BigInteger(a.getKey().getSinindex().toString()));

    }

    if (a.getKey().getCosindex() != null) {

        newInf.setKeyCos(new BigInteger(a.getKey().getCosindex().toString()));

    }

    if (a.getCof() != null) {

        newInf.setCof(a.getCof());

    }

    return newInf;

}```

这段代码是我在进行乘法求导时,对其中一个因子进行求导,剩余的不变时,要进行这个方法的调用,进行信息的复制。但是之后我查资料发现,JAVA中的基本类型(int,String等)和基本类型包装类(Integer,BigInteger等)这两类变量是不会导致内部信息变化的,所以其实在我这个第二次作业中,不进行信息复制也是可以的。不过我在这里就是想给以后的自己和看到这篇文章的读者们提个醒,在对同一个类进行多次操作且每次操作都要基于原始数据的情况下,不要忘记进行clone或是copy。不然这种隐蔽的错误真就写bug一分钟,debug到两点钟。

第三次作业——嵌套表达式求导

作业思路和心得

第三次作业较之前两次难度再次提升。我感觉难度最大的部分就是输入的读取和WF的判断。由于增加了嵌套表达式,整个输入的结构变得十分灵活而复杂。表达式里会有因子,因子里又会有表达式,这样对输入的处理是极大的困难。

为了提高性能,我采用了WF判断和输入的分析读取合在一起进行。先使用第二次作业中的Stringprocess方法将多余的符号去掉,再从头开始循环读取。读取的时候,判断括号数量是否匹配。其余WF在读取之前先遍历一遍字符串进行判断。

读取好各个因子后,就可以建立表达式树,建好后就按链式求导法则,对整棵树进行求导,求导后输出即可。在此,我要提一下我的第一版方法,就是将求导方法交给每个类内部自己管理,每个类内部也有自己的数据,这样,我最开始的想法是让类自己调用各自的方法,递归求导。但是我实现后发现,这样复杂度和空白数据量都太大了,而且逻辑也不清晰,就放弃了这个方法。最后选择了建树的方法。由于自己的数据结构基础也不够扎实,在学习建立表达式树的期间也费了好一番力气,查阅了大量网站资料。所以,我要告诉自己,基础要打好呀!(相信现在说为时也还不晚

程序结构分析

  • UML分析



    由于这次结构较复杂,所以为了减少代码量,我使用factor作为四种因子的父类,减少重复代码。此外,由于我的StringProcess和WF都是重新遍历了输入,所以与其他模块关联不大,我觉得这让我的这两个模块提高了可移植性和重用性,所以这两个模块是我较为满意的模块。表达式树的那几个模块,由于之前我对树的掌握不牢,导致这部分建树没有什么思路上的创新,按照固有方法和套路进行编写。也导致了之后输出的化简很难操作。

  • 复杂度分析







    由于程序复杂度的提升,方法的数量也大幅度提升,方法的复杂度倒是没什么巨大的增加。我分析原因在于我进行重构,选择表达式树之后,之前的一些复杂的大方法被我拆解为各个小方法放到类中,自己管理。所以方法的数量增加了,但是复杂度没什么暴增。

hack与被hack

第三次作业我自己的程序的bug主要出在WF判断这部分,我在本地自己测试时,就发现很多不该判WF的判成了WF,该判WF的却输出了结果。我对这些问题对程序打了很多个补丁,但是在强测和互测中还是发现了几个自己没有发现的点,导致了错误。这让我明白了自己构造数据的时候的方法有问题,我会在今后的作业的构造数据的过程中,注意改正,争取得到更好的测试效果。

在第三次互测中,随着程序体积的膨胀,完全阅读懂代码变得更加不现实了,所以我依旧采用第二次作业的方法。在互测中提交自己本地测试出现问题的用例,同时想一想别的常用方法会出现什么问题。效果也还是不错,很少有无效用例,大多都是找到了同组人员的bug的。

整体感悟思考

从寒假的一无所知到preview的有所了解到unit1的稍有理解,可以说这门课程让我一步步地走进了面向对象编程的世界。这一级级台阶也要感谢课程组的老师和助教们。

但是回头看来自己的三次作业,发现面向对象的一些常用的pattern还没有灵活运用,一些常用的思想也还没有深入理解。这些都需要我在今后的课程中努力学习,尽力理解的东西。

我也在第一单元作业的历练中,发现了一个适合自己的写测结合的方式。我喜欢每写完一部分就认认真真、仔仔细细地测试一遍这一部分的功能是否正确。直到在我看来,这部分写完的代码功能上完全没有问题我才会继续写下去。这样我感觉虽然用时较多,但是写起来让我自己感觉更加安心,同时也让debug的难度有所减小。我感觉是适合我自己的编写方法。我会在今后的作业中,继续使用这种方法,希望能够取得良好的效果。

BUAA_2020_OO_第一单元总结的更多相关文章

  1. OO第一单元作业小结

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

  2. BUAA面向对象设计与构造——第一单元总结

    BUAA面向对象设计与构造——第一单元总结 第一阶段:只支持一元多项式的表达式求导 1. 程序结构 由于是第一次接触面向对象的编程,加之题目要求不算复杂,我在第一次作业中并没有很好利用面向对象的特点, ...

  3. 2019_BUAAOO_第一单元总结

    前言 OO第一单元共有三次作业,分别为多项式求导.带有三角函数与幂函数的表达式求导.带有嵌套表达式因子的表达式求导.虽然这三次作业都离不开求导,可是每次作业的复杂度都是大大递增的.对于习惯于面向过程编 ...

  4. OO第一单元作业总结

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

  5. OO第一单元总结

    OO第一单元作业总结 一.前言 开学四周,不知不觉已经做了三次OO作业.事实上,每一次作业对我来说都是很大的挑战,需要花费大量的时间和精力来学习. 虽然学得很艰苦,但最后还是连滚带爬地完成了.(好惨一 ...

  6. OO第一次博客作业--第一单元总结

    OO第一单元总结 面向对象设计与构造的第一单元,对“面向对象”的概念还根本不理解不熟悉,只觉得需要“分模块”,但不知道怎么分,分多少模块,怎么根据需要的模块的功能建立类.学习的进度又太慢,根本跟不上出 ...

  7. OO第一单元总结(表达式求导)

    写在前边:第一次接触面向对象语言,编程思想仍然不可避免的有以前面向过程的影子.从第一次作业的完全面向过程,到第二次学会剥离各个类互不影响到第三次作业的先构思面向对象的基本程序架构再编程.虽然程序有些地 ...

  8. OO第一单元优化博客

    OO第一单元优化博客 第一次作业: 合并同类项+提正系数项+优化系数指数0/1=满分 第二次作业: 初始想法 一开始是想以\(sin(x)​\)和\(cos(x)​\)的指数作为坐标,在图上画出来就可 ...

  9. 【BUAA-OO】第一单元作业总结

    #OO第一单元作业总结 #确认存活,爱学习,爱北航,爱OO 一.三次作业分析 1.第一次作业 1.1 程序结构 对方法的度量: 类的内聚和相互间的耦合情况: 类图: 优缺点: 优点大概没什么优点,毕竟 ...

随机推荐

  1. 泰拉瑞亚Linux主机打造指南

    最近玩了泰拉瑞亚,一个2D版的我的世界,但苦于steam的联机太过不靠谱,经常会出现和朋友之间联机失败的问题,所以我把服务器放到了部署我博客的服务器,这样就可以通过IP直接让好友加入游戏了! 首先是购 ...

  2. 上周 GitHub 热点速览 vol.09:手撕 LeetCode 一日 star 破两千

    作者:HelloGitHub-小鱼干 摘要(用于 公众号/博客园等地方):上周 GitHub 趋势榜相较上上周就如同前故事一般,跌到不行,无论是新晋开源小项,还是坚挺老项目,Star 增长量都不如之前 ...

  3. 广告行业中那些趣事系列6:BERT线上化ALBERT优化原理及项目实践(附github)

    摘要:BERT因为效果好和适用范围广两大优点,所以在NLP领域具有里程碑意义.实际项目中主要使用BERT来做文本分类任务,其实就是给文本打标签.因为原生态BERT预训练模型动辄几百兆甚至上千兆的大小, ...

  4. Java 抽象类 抽象方法 使用说明

    知识点 什么是抽象类 抽象类与普通类主要两点不同: 1.在类的修饰符后面多了一个abstract关键字 2.抽象类是不允许通过new来实例化的 由于抽象类不能通过new来实例化,所以基本上是在继承中当 ...

  5. js之重写原型对象

    “实例中的指针仅指向原型,而不是指向构造函数”. “重写原型对象切断了现有原型与任何之前已经存在的对象实例之间的关系:它们引用的仍然是最初的原型”.——前记 var fun = function(){ ...

  6. 开源一个使用python和pyQT实现的产测工具

    导语 之前给朋友友情开发的一个产测工具,现开源,有需要的朋友可以在这个基础上进行二次开发. 操作界面如下 主要特性 自动识别启动信息,然后进入产测写入状态 序列号和MAC地址自动按指定数目增加 每次操 ...

  7. NLP(二十五)实现ALBERT+Bi-LSTM+CRF模型

      在文章NLP(二十四)利用ALBERT实现命名实体识别中,笔者介绍了ALBERT+Bi-LSTM模型在命名实体识别方面的应用.   在本文中,笔者将介绍如何实现ALBERT+Bi-LSTM+CRF ...

  8. 【PG】Greenplum-db-6.2.1的安装部署

    目录 1配置host文件(所有节点) 2 配置用户 3 配置/etc/sysctl.conf文件 4 limit文件,后面添加[不影响安装] 5 安装greenplum-db-6.2.1-rhel7- ...

  9. Java反射之Class类

    接下来的几章,我们谈一谈java的反射机制. 反射就是从一个java类中映射出一个java类或是一个实例.通常在很多框架中都用到反射,比如常用的ssm框架,在配置文件中总是会写到类的全名,框架通过读取 ...

  10. Asp.Net Core 中IdentityServer4 授权原理及刷新Token的应用

    一.前言 上面分享了IdentityServer4 两篇系列文章,核心主题主要是密码授权模式及自定义授权模式,但是仅仅是分享了这两种模式的使用,这篇文章进一步来分享IdentityServer4的授权 ...