三次作业,三次成长

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

作业思路和心得

第一次作业的要求只有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. PKI详解

    预备: 一.密码基元 二.密钥管理 三.PKI本质是把非对称密钥管理标准化 PKI 是 Public Key Infrastructure 的缩写,其主要功能是绑定证书持有者的身份和相关的密钥对(通过 ...

  2. python自己做计算器

    题目: exp = '1 - 2 * ( (60-30 +(-40/5) * (9-2*5/3 + 7 /3*99/4*2998 +10 * 568/14 )) - (-4*3)/ (16-3*2) ...

  3. snmp服务配置

    snmp服务配置 1. 检查是否安装 snmp rpm -qa |grep snmp 如未安装 rpm –ivh  加包名 (net-snmp-utils 为各种工具包) 2.服务开启 service ...

  4. CSS+JS相应式导航菜单

    响应式导航菜单 响应式导航菜单就是当网页在其他不同视口的样式,不同的设备需要不同的样式 需要掌握的知识 - 掌握媒体查询,如果你不是很懂那就看我写的CSS响应式布局 掌握CSS重的display:no ...

  5. Typora[MarkDown编辑器]+(PicGo+Github+JsDelivr)[个人图床] ,开启你的高效创作

    使用Typora搭配Picgo开启你的高效创作 0x00 一切都要从MarkDown说起 富文本语言的弊端 平常我们最常用的写作工具,无非是富文本编辑器中的代表--微软家的Office Word.这种 ...

  6. GitOps入门与实践:如何集成Git和K8S?

    也许你之前听说过GitOps,但是对其并不了解.在本文中,我将对其进行简单介绍,它其实是一个应用程序开发和管理中的一个术语,其核心思想是将应用系统的声明性基础架构和应用程序存放在Git的版本控制库中. ...

  7. python-面向对象小结

    面向对象 小结 1:面向对象:就是一种编程思想 简称oop,指挥某某完成能完成的功能 2:面向对象与面向过程的优缺点 : 面向过程: 优点: 复杂问题简答化(一步一步解决), 流程化, 缺点:机械化 ...

  8. vue 动态加载图片路径报错解决方法

    最近遇到图片路径加载报错的问题 之前一直都是把图片放到assets的文件下的.总是报错,看到一些文章并且尝试成功了,特意记录下 首先先说明下vue-cli的assets和static的两个文件的区别, ...

  9. PHP的json_encode和json_decode的区别

    经常搞混的两个PHP函数: json_encode()是对变量进行json编码 json_encode()为要编码的值,且该函数只对utf8编码的数据有效 json_decode($json)对jso ...

  10. docker 技术全面整理

    docker 和 vm 虚拟机技术比较像,但又有一些区别. vm 像真机一样有 BIOS ,有硬盘,有网卡,声卡,可以安装操作系统, win7 win10 macOS ubuntu centOS,有好 ...