OO第一单元博客作业

黄拓远-22371180 学生 2024-03-19 23:03:54

目录

hw1

UML类图

代码架构与解题思路

构建过程中出现的bug

添加的优化

复杂度分析

hw2

UML类图

 新增类以及相关思路

在构建过程中出现的bug

代码算法方面进行的一些更改

添加的优化

复杂度分析

hw3

UML类图

新增类以及思路

添加的优化

构建中出现的bug

复杂度分析

心得体会

未来方向


2024面向对象设计与构造第一单元


hw1

UML类图:

代码架构与解题思路:

第一次作业需要我们手动输入一个表达式,最后将表达式化为最简的形式。并且介绍了基本概念,其中表达式含有多个项,项中含有多个因子,因子可以是表达式,数字以及变量。所以我便自然而然的先创立4个类,并且设置一个因子接口,其中上述三个因子为其子类。表达式类中有个Arraylist变量存项,项中有个hashset变量存因子。此时就会产生一个问题,那就是表达式可以存项,项又可以存表达式,子子孙孙无穷尽也。因此我之后几乎所有的解析表达式方法都有递归下降的算法。那么如何解析表达式呢?首先是建立一个Lexer类解析这个字符串,其作用便是将其中的数字,字母,符号一个个分离开来。接下来便是Parser类,其作用是根据Lexer解析的因素建立一个表达式输,这个表达式树涵盖了这个字符串表达式的全部内容。接着便是Simplify类,该类的作用是将这个表达式树化简,使表达式中的每个项化简为要么只有一个表达式因子(该因子中有若干项),要么没有表达式因子。但是需要注意的是化简完之后的表达式还是一个树的结构,每个项之间并非并列的关系。所以我再引用了Merge类。该类的作用便是将分布在不同分支的项合并到一个表达式中。最后使用Short类将最终的表达式进行同类项合并,主要做的是性能上的优化。

构建过程中出现的bug:

除去一些低级错误所造成的bug,值得一提的便是深浅克隆产生的bug了。例如在计算(x)^2的时候,我一开始采取的是浅克隆,也就是对一个项进行克隆的话产生的新项与旧项因子是共用的,这样的话在计算的时候便会出现问题,当计算上述表达式时,结果仍然为x,就是因为因子共用导致添加因子的时候因为相同仍然为一个因子,若要解决上述问题,可以采用深克隆的方法。如此一来二者的因子不共用,这样便会是两个因子,答案便是正确的了。

添加的优化:

1、将表达式各项进行同类项合并,这样所得的表达式长度会大大减小。

2、如果表达式中含有正项,那么便将其放在第一个位置。如果表达式的第一个符号为"+"号,那么便将其去除。

3、如果表达式中含有1*或者是*1,但是前面或者后面又不是数字,那么则将其去除。

复杂度分析:

我在第一次作业中复杂度最高的便是我的Term类中的tostring函数了,因为这个函数重复运用了一些别的函数以求值进行if判断,这十分不利于性能的提高,实际上只需要求一次然后将该值存起来就好了。还有便是Parser中的ParserTerm函数,这个函数也是在if判断的时候引用次数过于多,在之后的作业中我进行了相应的更改。


hw2

UML类图:

 新增类以及相关思路:

第二次作业新增了两个因子,为指数因子和自定义函数因子。其中,指数因子的指数可以为任意因子,自定义函数因子便是用之前给的定义拿实参去替换形参从而将其转化为表达式。在这里我便新增了Exponent类、Function类和Function Definition类,并把前两个都接到因子接口当中,其中Exponent类有一个参数便是Factor,而Function类中有一个参数是FunctionDefinition,用于记录该函数的定义便于之后的替换。本次新增的难点便是如何把函数换为表达式以及指数又可以嵌套因子的情况。先说说第一个,将函数换为表达式则是使用递归替换的方法,先从函数定义的表达式开始,一层层往下寻找和形参字母相同的变量因子,然后用实参将其替换,替换时还要一并复制该变量的指数。至于指数嵌套因子,则在有递归下降的地方多加一种情况也就是指数的情况,继续递归其中的因子,尤其是simplify类中的方法有了较大改动,这些改动以及新增不出现问题是这一次作业很大的挑战,另外,随着二者的添加,所计算的数据也随之大大增加,在强测时十分容易出现runtime error或者爆内存的错误,如何让计算最为快速也是一大挑战。

在构建过程中出现的bug:

1、深克隆时遗漏参数,本人在深克隆表达式的时候,便遗漏了表达式的指数这一参数,导致了一些问题出现。深克隆时务必克隆该类的所有参数,不可遗漏任何。

2、自定义函数替换参数时将替换过的实参当作之后要替换的形参。例子如下:

1

h(y,x)=y+x

h(x,1)

正确答案应该是x+1,但是由于我替换掉了第一个实参的时候表达式变成了x+x,导致我在替换第二个实参时将两个x都进行了替换,得到的错误答案为2。我的解决方法便是在前面解析函数定义的时候将其变量处都加上一个特殊符号。例如上述定义我便会解析为h(#y,#x)=#y+#x,这样之后替换的时候也不会出现相同的字母。

代码算法方面进行的一些更改:

因为本次作业所需要计算的数据量大大增加,导致我原来的算法无法计算一些数据,因此,我对其做了如下修改:

1、原本指数的解析从由外而内变为由内而外。例如一个强测样例:

((x^8)^8)^8

原先我的做法是,先计算指数,再化简里面的各个项,但是这会导致项变得非常多,计算完指数便变成了8个((x^8)^8)项,括号再多那就更复杂了,而改进之后多方法是先化简内部的项,再进行指数计算。这样一来就先将里面变成了x^64,之后也就是重复计算这一项,算力明显减小。

2、一边化简就要一遍合并,我再hw1的算法是先将所有的因子全部算出来,到最后一起合并,但是这样的话会出现一个很大的问题,例如

(1+1+1+1+1+1+1+1)^8

原先我的做法是先将其展开成8^8个1,再访问每个项合并,但是这样访问的项数太多了,如果先化简变成(8)^8,再进行计算,那么便很快得出答案。

3、原先的比较只要比较二者的x指数是否相等来判断是不是可以合并,但是现在加了指数,比较两个项也成了一个很大的问题,例如如果两个项除了指数因子之外其它都相等,那么又要比较指数内部的因子,而指数内部的因子可能为表达式,而想要比较表达式又要将表达式排序,但是排序的内核又是比较。因此我写的compare函数是和sort函数两个嵌套在一起的,并且还是嵌套式的递归下降。

添加的优化:

本次作业我也添加了一些优化部分,例如Delete类中的方法便是递归删除含有数字0因子或空表达式的项以及项数为0的表达式,这样计算0*h(x)的时候如果h(x)十分复杂我便可以节省很多计算他的时间。

复杂度分析:

本次复杂度较高的方法都是与Factor有关的方法,因为factor有五种,因此与其有关的方法会多做一些判断,从而引用多个类的方法。


hw3:

UML类图:

新增类以及思路:

 本次作业就是新增了一个导数因子dx(因子),但是我并没有新增数据存储类,因为我将dx里面的因子全部视为表达式,只要对我的表达式类加一个参数是否为导数就行了。在Simplify的时候如果这是个导数类的话就化简完了之后对其求导再化简。因此我添加了一个Derive类用于计算表达式的求导。总的来说本次作业增加的不多,也就是增加了对项的求导计算而已。

添加的优化:

本次作业我对指数里面的因子进行了提取公因式变成括号外面指数的计算,然后和原字符串做对比,最后取长度小者。

构建中出现的bug:

在提取公因式的时候出现了将负数最大公因式一同提取出来的错误,导致指数因子的指数为负数,不符合规范,改进便是将数的绝对值拿出来提取而不是原数。

复杂度分析:

本次作业的复杂度和上次没有太大出入,就不列出表格进行展示了。


心得体会:

这一个单元的作业核心思想还是递归下降,想要一次访问完所有的数据方法几乎都设计递归下降,这让我对其有了一个很好的学习以及掌握,我在这方面的代码能力也有了很大的提高。另一方面就是算法的斟酌,有时候计算出相同答案但是方法千差万别,而其中经过的道途差别可能更加巨大,这也启发了我在选择算法时不要想到什么就鲁莽使用,而是考虑该算法的代价小不小,方法性能好不好。这样才能打出好代码。


未来方向:

我认为可以稍微修改一下第三次作业的形式,因为第三次作业添加的导数因子其实和表达式因子如出一辙,可以再添加一个别的新因子具有嵌套属性例如三角函数或者是别的新算法例如除法,这样同学们或许对自己的代码会有更好的掌握。

...全文
106 回复 打赏 收藏 转发到动态 举报
写回复
用AI写文章
回复
切换为时间正序
请发表友善的回复…
发表回复

301

社区成员

发帖
与我相关
我的任务
社区描述
2023年北航面向对象设计与构造
学习 高校
社区管理员
  • YannaZhang
  • CajZella
  • C_ecelia
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧