一、程序分析

1.1第一次作业

  第一次作业是简单的多项式求导,甚至没有括号嵌套。但是,就是这个在如今看来如此简单的作业,由于俺寒假过于起飞,pre没做,正则表达式也不会(属实拉跨),一度想用c语言字符串的方式一个一个读入来解决(没想到后面需要用到这么朴素的方法,也可能是我不会正则的应用)。还是在室友的提醒下,速成了正则的皮毛,然后根据第一次上机的代码提示(第一次上机我甚至不知道要在网页上commit才算提交。。。),写了一个表面面向对象(因为有三个类。。。),实则面向过程的程序。

  程序类图如下:

  

  • MainClass
      在这个主类里只做数据的输入,预处理(去掉空格,替换**,分割项)以及输出。这也算有了一丢丢面向对象???
  • Poly
      poly有聚的意思,我也没搞懂我这里面的方法和聚有什么关系,关系真不大,改名为Factory也许更合适。这个poly,毫不客气地面向过程,要不是有checkstyle,我恨不得一个函数写完(偷笑.jpg)。里面用正则表达式匹配每一个单项,总结出这个项的指数和系数(即term类)。然后是建了一个哈希表,以系数为key,合并同类项。
  • Term
      这个就是一个含有两个BigInteger 的结构体,只有get和方法,来存储系数和指数

  复杂度如下图所示:

  这次作业耦合度很高,ptfd的求导和输出都是在一起的。

1.2第二次作业

  第二次作业是增加了三角函数因子,同时也增加了括号嵌套。对括号嵌套我采用了递归下降的处理方法,对多项式的解析仍然是采用一个多元组的 ArrayList 来存储的,求导的话仍然是对每一个多元组求导。可以说方法和第一次作业一样,只是不会用正则表达式了。

  程序类图如下:

  • Main 
      这个主类和第一次作业一样,有一点不同就是我在每一个括号的内部开头加了一个 + 号,现在来看其实没必要,单独处理一下符号就行了。然后还有就是我对最后答案的化简没有直接在求导过程中化简了,而是单独用 replaceAll 来化简,其实这对效率的提升有很大帮助。
  • Poly 
      这个类这一次有了很大的变化。由于不会使用正则表达式了,我采用一个一个字符往下读的做法,遇到表达式因子就递归处理,其他的因子都单独写了函数处理。然后同样的解析成四元组(指数,x的幂,sin(x)的幂,cos(x)的幂)列表。求导的话对每个四元组单独处理。
  • Term 
      四元组(指数,x的幂,sin(x)的幂,cos(x)的幂)。这次除了get和set以外有了重写的tostring函数了。算一个进步吧哈哈哈。
  • Thrd 
      这是一个三元组(x的幂,sin(x)的幂,cos(x)的幂)。我是为了合并系数相同的同类相而准备的,用这个三元组来作为key,重写了 hashCode 和 equals ,利用 HashMap 来快速寻找以便合并。其他的优化我也是有心无力了。。。

  复杂度如下:

  这次怎么说呢,这个递归下降不是标准的递归下降,是我自己的方法,所以一度出现了bug。好在后面改过来了。

1.2第三次作业

  无效作业,就挺难受的

  第三次是在sin和cos里面有了表达式因子的嵌套,另外加了格式检查。这次作业可以说是我面向对象的一大改变,终于有对象那味了。我不再是一个 Term 了,而是弄了三个因子类,系数和x是 Nx ,然后是 Sin 和 Cos 。这些类里面都有了自己的方法,我也重写了 Clone 和 equals ,实现了一个独立自主的类。

  程序类图如下:

  • Main 
      这个函数先是对格式进行了检查,格式检查的主题架构和后面解析多项式是一样的,都是递归下降方法处理。其他的方面和之前的第二次作业一样。
  • Wf 
      这个就是我单独写的格式检查类,采用递归下降方法,但是对于指数小于50的判断我放在了后面的处理中。
  • Poly 
      和第二次作业一样,没有别改变。
  • Exp 
      这次我不再是一个poly打天下了,单独将表达式列了出来,也是为了后面求导的方便。表达式有自己的添加 Term 方法,还有表达式乘表达式的方法以及一些基础的克隆等方法。它的实质没变,就是一个 Term 的 ArrayList 。
  • Term 
      这次对数据进行了新建类的处理,所以更加集中于方法的设计。求导,相乘,克隆,特别关注了合并优化。对于三角函数,分别为两个不同的三角函数因子构造了 ArrayList 以存储不同表达式的三角函数。
  • Nx 
      这个是x和系数的综合,单独为了系数写一个类没有必要,就把他们和在一起了。
  • Sin  Cos 
      这两个三角函数因子,由表达式因子和幂组成。引用了 Exp

  程序复杂度如下:

  每一个类,都有自己的求导函数和加法乘法函数。每一个求导函数返回的都是一个 Exp 统一了起来,这样就不要再去单独写项乘多项式啥的了。同时每一个类也有自己的 clone  equals 以及 tostring 。

  当这些类可以被称作独立的的类的时候,即他们都有自己的数据和方法且耦合度极低时,本层的求导就只需本层的特殊之处加上下层.diff就行,也不再需要考虑下层的具体过程了,这或许就是面向对象了吧。

二、BUG

  第二次作业我出现了一个大bug,我的递归函数,按理来说遇到 ) 需要返回,但是我当时没想透彻,还继续往下特判了紧接着 * 的情况,导致程序不能正常返回,只能碰到字符串结束符返回。在互测的时候被hack了很多次。其实互测的时候同学如果没看我代码就不会认为我是同一个错误,所以被痛击。。。

  然后互测结束我修改了代码,也正是修复这个bug使我去掉了很多冗余代码,结构也变得清晰了起来。代码行数的减少是肉眼可见的,圈复杂度 slt 函数由于直接没了,也减少了不少。

  我自己是如何测自己的的程序的呢?为了不那么辛苦的调试(主要是只会printf),我是写一个功能就进行测试,这样一来,至少在这三次作业,最后测的时候我的bug很少,就很省事。

  记得在判断格式的时候,我出现了一个bug,由于那个测试数据格式判断递归层数较多,我是一步一步减少递归层数,找到最少的但我又出错的那个数据。然后我对每一个递归函数,开头都加了一个: System.out.println("-->xxx"); ,结尾加上 System.out.println("xxx-->"); ,xxx就是该函数名称,箭头代表进入和出去,这样一来就较为清楚了。

  不过确实我觉得我还是得学学怎么用调试功能才行。

  关于如何hack他人的代码,我本人是不太想做这样的事,特别是这会使其他同学丢分。当然我明白,这样做可以激励同学写出更加完美的代码,减少bug,我认为要找同学的bug可以先测一组自己构造的边界数据。然后可以阅读其具体代码考虑其没注意到的点。

  阅读他人代码是可以学到许多东西的,只可惜我看到别人的代码就头大,感觉无从下手。还是说明我对代码这一块比较生疏。不过目前我还是能够读下一整个代码,对整体有把握了,但是除了明显的bug,其他的我还是看不出什么明道,希望在之后的学习中能够多读代码,提升自己的能力。

三、从面向过程到面向对象

  真正知道面向对象得是第三次作业。

  第一次作业是面向过程的,然后我重写的第二次作业,由于没有理解什么是面向对象,我还是面向过程。

  从第二次作业到第三次作业,虽说是重构,其实其修改量可以说是重写。我真正写出了独立的类,他们都有自己的数据与方法,都是独立的,完全去掉也不影响,也方便扩充。我也感受到了面向对象的便利之处。在我求导和得出答案字符串的时候,对于本层的求导,我只需要设计本层特有的方法,而本层求导必定涉及到下一层,例如对多项式的求导涉及到多项式的每一项,而下一层的求导结果我只需要打出 下一层.diff 即可。然后 tostring 、 clone  、equals 都可以这种方式完成,既减轻了编写代码的复杂度吗,又降低了耦合度使得增加了可扩展性。这便是我目前对面向对象的理解,希望在接下来的学习中能够加深完善我的理解,学好这门课!

四、总结与感悟

  在第二次作业的时候,我们上了研讨课,有同学分享了递归下降的方法,当时课上没怎么听懂,也不好意思提问,怕又是一个我不知道大家都知道的东西(这种情况对我来说太常见了,提问只会耽误大家时间,怕了怕了)。课下我去网上搜了搜资料。嗯?编译原理?文法分析?都不会啊!我硬着头皮进去,好家伙,LL0文法,左递归处理,劝退劝退。罢了,我还是自己写吧。。。。

  然后在我写这个的时候,又是十分纠结。本身JAVA也不太熟,写着写着也没底,很慌,万一折腾了好久是一个错的怎么办。(真的现在我都不晓得为什么不敢试错,怕浪费时间,明明搞别的有的没的的事情我又有的是时间。可能是想到大家都会都写完了只有自己不会着急吧。。。唉,我对自己也挺无语的)别的事情我都挺头铁的,一到学习我就畏畏缩缩,不敢尝试,害怕犯错。

  想想写写改改,抱着准备重写的心态运行了一下,哎,可以运行呐。自己再看了一下自己的代码,当然可以运行啊!咱也不知道啥是递归下降,就用我这个吧,递归下降怎么说呢,终究是无缘吧!??

  后面我才发现原来有讨论区,原来讨论区有热心的同学通俗的分享了递归下降。

  我写的也是递归下降,可能这次下降我没懂是啥意思,感觉就是个递归。但终究完成了作业。

  然后不得不提我的无效作业了。

  上个星期的星期天,我在写完其他步骤只剩格式检查的时候(我单独写了个格式检查),感觉轻松了许多,晚上我自己首先是测了指导书给的数据,没问题。然后又针对性地构造了一组复杂的数据,测了也没问题。

  于是我第一次提交,21:22,wa了两个week点。慌了,又构造了好多数据,求助室友一起构造了数据,终于找到了原因。我格式检查的时候认为三角函数里只有x和sin,cos开头才不要加括号,没想到x地幂次方也不需要加括号,改了急急忙忙交了,21:45,week点还是有一个没过。

  现在知道原来常数因子也可以不要加括号。。。。

  唉,忙活了三天。现在觉得其实也没多复杂,不需要搞三天之久,可当时我改一点点就有bug,然后费尽心思找bug,所以搞了三天之久。当时感觉还挺有收获,终于对面向对象有了一定地了解。

  没得机会和同学互测,没得机会检验自己的化简力度,没得机会拿到基本的作业分数。

  怪我没认真看指导书。当时也是大概知道要做什么了,看到有同学在群里说 sin(-x) 不合法,要改成 sin((-x)) ,便开始自己埋头苦写。

  就挺失落的,直到现在我才敢(必须)再次打开我的idea看我的代码。

  虽说以至少学到了知识分数不重要来安慰自己,可是各位谁不看重分数呢?谁不呢?

  当时我都不想,也没有动力去继续学习java这门课了,再怎么在优化上面搞也得不会这次无效作业扣的分。

  感谢助教和老师安慰了我,也感谢给我提供帮助室友同学们!

  没得办法,都已经发生了,也只能通过改变自己得想法来继续前行,就很无奈。愿大家都不会遇到我这种情况(事实上应该也不会),学到知识的同时也能取得满意的成绩!

最新文章

  1. VS项目中使用Nuget还原包后编译生产还一直报错?
  2. 【转】理解 PHP 依赖注入 | Laravel IoC容器
  3. 1007. Maximum Subsequence Sum (25)
  4. Python文档
  5. ASCII码排序(未完)
  6. JVM基础02-class文件
  7. 自研框架wap.js实践
  8. .NET十年回顾
  9. nodejs+mongodb+vue前后台配置ueditor
  10. Java内存泄漏分析系列之五:常见的Thread Dump日志案例分析
  11. 第一次C语言程序设计
  12. Linux下mysql定时自动备份并FTP到远程脚本
  13. SNF开发平台WinForm-平板拍照及扫描二维码功能
  14. 细数php里的那些“坑”
  15. MVC 第一章(下)
  16. xampp 80端口被占用后这么办??解决了
  17. 10个造型奇特的css3进度条(有的html被编辑器转义了,上面的代码还是OK的)。。。转载
  18. 使用Intel IPT技术保护您的帐号安全
  19. 【转】VMware网络连接模式—桥接、NAT以及仅主机模式的详细介绍和区别
  20. springMVC参数绑定JSON类型的数据

热门文章

  1. 小米手机MIUI12获取hci.log的方法记录
  2. redhat单网卡配置多个IP
  3. curl 与 header 及 file_get_countents 访问内容时的区别
  4. web server 接口调用
  5. Unity WebGL与JS脚本交互
  6. Appium自动化测试之键盘操作pressKeyCode()方法(Android特有)
  7. MeanShift 均值漂移算法
  8. DHCP 服务详解
  9. 汇编debug工具Dosbox使用
  10. Unity中常用的几种读取本地文件方式