BUAA OO Unit1:表达式的解析与化简

BUAA OO Unit1:表达式的解析与化简

作者的碎碎念:第一单元 基本目标可以被一个例子总结,

s i n ( ( x + 2 ∗ x ∗ ∗ 2 − x + y ) ) ∗ ∗ 3 − d y ( y ∗ ∗ 3 + y ∗ ∗ 3 ∗ 2 ) sin((x+2*x**2-x+y))**3-dy(y**3+y**3*2) sin((x+2x2x+y))3dy(y3+y32)
化简成
s i n ( ( 2 ∗ x ∗ ∗ 2 + y ) ) ∗ ∗ 3 − 9 ∗ y ∗ ∗ 2 sin((2*x**2+y))**3-9*y**2 sin((2x2+y))39y2
第一单元的作业,是面向对象的入门。但非常遗憾的是,由于面向过程到面向对象思维转变的困难,以及第一单元前两周作业与本人两门专业大课期末缓考冲突,我并没有完全的使用面向对象。所以本篇博客介绍的作业完成方法更倾向于算法和结构的统筹 (我认为比面向对象思想好理解,好实现)

同时,本次单元中颇为重要且细节繁多的“文法”,我认为他更面向于使用面向对象思想的同学。因此如果同学在阅读文法方面 不耐烦 有困难的话,我认为参考本人的作业方式也未尝不可。
我非常遗憾自己没能在提交期限内完全使用面向对象思想完成作业,但是如果你现在像当时的我一样抓耳挠腮完全不知道如何下笔,那么或许我的这篇blog会对你有所帮助。

总体

本次作业的基本逻辑就是
expression = term + term + term * …
term = factor * factor * factor …

所以主要的类就是三种 expression、term 、factor
一个expr包含一系列term,关系是相加 => Arraylist terms
一个term包含一系列factor,关系是相乘 => Arraylist factors

我作业的核心思路就是:找到组成多项式的核心。
多说无益,我们用作业来举例。

第一次作业

第一次作业关系图+ 作业要求化简
第一次作业只涉及到 x , y , z x,y,z x,y,z的“+,-,*,^”四种操作,

  • Expression => polynomial
    • 找到poly的核
      对于一个基本多项式,
      ∑ k x a y b z c \sum{kx^ay^bz^c} kxaybzc
      非常容易就想到他的内核就是 k x a y b z c kx^ay^bz^c kxaybzc,所以抽象来看 只需要一个四位数组 <coeff,a,b,c>分别表述系数和xyz的幂次,一系列这样的数组就构成了一个项,一系列项就构成了表达式。
    • 类的构成和作用
      我认为抽象地描述很难理解,我们直接用一个例子来说 ( ( x + 1 ) ∗ ∗ 3 + x ∗ y + y ∗ x ) ((x+1)**3+x*y+y*x) ((x+1)3+xy+yx)
      在这里插入图片描述需要注意的是,一个term最后可能(且大概率)会变成一个expr:即一系列monomials的和。
      同时monomial切合了factor的<coeff,a,b,c>的特质,所以笔者就把monomial作为了factor引用的对象。一系列monomials的和也就构成了一个poly,但笔者因为比较懒,没有新建一个poly类,所以直接在term里做了一个finalFactor的数组,这个数组里面factors的关系都是和。
      第一次作业的基本逻辑到此也就告一段落,优化的部分其实很简单,只需要在解析完成的expr(poly),加一个merge方法,一个for循环遍历poly的所有的monomials,如果遇到<coeff,a,b,c>中,<a,b,c>完全相同的项,就对他们的coeff进行加法合并处理即可。
      注:在这里笔者的个人建议是,新new出来一个空ArrayList,防止对原先的ArrayList动态删减的时候造成并发修改错误。
  • 输出优化
    输出优化基本就是遍历poly中的monos,然后对<coeff,a,b,c>这个数组特性每一项进行特判。
    • coeff == 0 : 跳过该项
      coeff == 1 : 跳过该系数
    • a(b,c) == 0 : 跳过该变量
      a(b,c) == 1 : 跳过该变量系数
      a(b,c) == 2 : 把变量写成x*x 而非 x**2,因为前者更短
      其余就正常输出即可。
  • 总结:第一次,乃至后续两次,都是向下再向上的过程。通过对expr的解析,把他从一个简单的字符串,变成一系列我们可以利用的部分的组合,从而完成作业。

第二次作业

在这里插入图片描述+ 作业要求
和上次作业对比,第二次作业新增要求就是增加了三角函数和自定义函数

  • Expression => Polynomial
    • 找到poly的核
      继承上一次作业的想法,我们仍然要找到这次poly的core ∏ s i n ( ) ∏ c o s ( ) ∑ k x a y b z c \prod{sin()}\prod{cos()}\sum{kx^ay^bz^c} sin()cos()kxaybzc
      注:为什么我不选择用 ∏ s i n ( ) ∏ c o s ( ) k x a y b z c \prod{sin()}\prod{cos()}kx^ay^bz^c sin()cos()kxaybzc做基本核的原因是这样可以充分继承上一次作业已经解析好的部分。主要是懒
      那么对比上一次的core1: k x a y b z c kx^ay^bz^c kxaybzc,这次的core是一个什么变化形态呢?可以被认为是一系列连乘的sin和一系列连乘的cos以及一个上一次的poly构成。
    • 类的构成和作用
      通过观察类图发现我的新增类只有一个Tri和一个FunctionDefiner。
    1. Tri:其实可以用继承,但我没有:),抽象出来三角函数的特性,一个三角函数壳子和内部的一个expression,tri(expr)。
    2. FunctionDefiner:我前面根本没提到自定义函数如何解决,是因为我的自定义函数根本没到factor的层次就已经被我吃掉了:)用一个hashmap<函数名,函数内容>定义一系列函数。然后在handle(对字符串的预处理)时,就做好从实参到形参的字符串替换。然后自定义函数就消失了。
      注:最好把原函数的xyz变成大写,否则可能会出现循环替换的情况。
      抽象的话说的太多,不如用一个例子来解释。
      在这里插入图片描述到此第二次作业解析我们也做完了。
  • 输出优化
    除了第一次的优化,这次的新增优化还有以下几点,不完全是在输出做,很多是在项内合并就做好了
    • 项内合并
      sin(expr) 的expr == 0 :删除该项
      cos(expr) 的expr == 0 :删除该因子
      sin/cos(expr) 的power == 0 : 删除该因子
    • 输出优化
      基本同第一次一样
    • 三角优化
      笔者因为太懒没有做三角优化,但这里仍然列举出适合笔者架构的三角优化
      sin(2x) = 2sin(x)*cos(x) : (项内)对于一个sin列cos列,寻找expr相同项,删除cos项,新增sin项
      sin(x)^2 + cos(x)^2 = 1 : (项间)对于两个term,如果能找到一个sin和一个cos他们的expr相同,power均为2,且其余sins,coss,非三角函数因子列均相同,则删除一个term,同时删除另一个term对应的sin项或cos项
  • 总结:第二次作业我是重构的,重新写完第一次作业的架构之后接续开发的第二次作业,所以花费了很长时间,同时寄掉了强测:)花了7个小时修改了强测所有bug,然后为第三次作业打下了非常坚实的基础。

第三次作业

在这里插入图片描述+ 作业要求:
新增自定义函数嵌套和唯一出现的一次求导

  • Expression =>Polynomial
    • 自定义函数嵌套的部分,笔者在上一次作业已经实现了,通过循环替换字符串,只要表达式中有函数符号fgh,就替换,所以这部分非常轻松的搞定!
    • 求导,在笔者的架构下求导非常容易实现, ∏ s i n ( ) ∏ c o s ( ) ∑ k x a y b z c \prod{sin()}\prod{cos()}\sum{kx^ay^bz^c} sin()cos()kxaybzc
      在这个架构下,用:前导后不导+后导前不导的思想
      1. 首先求导因子出现,dx(parse(expr)) -> dx(poly)
      2. 对一个 t e r m = ∏ s i n ( ) ∏ c o s ( ) ∑ k x a y b z c term = \prod{sin()}\prod{cos()}\sum{kx^ay^bz^c} term=sin()cos()kxaybzc
        t e r m ′ = ( ∏ T r i s ) ′ ( ∑ k x a y b z c ) + ∏ T r i s ( ∑ ( k x a y b z c ) ) ′ term' = (\prod{Tris})' (\sum{kx^ay^bz^c}) + \prod{Tris}(\sum{(kx^ay^bz^c))'} term=(Tris)(kxaybzc)+Tris((kxaybzc))
        = ( ( ∏ s i n ) ′ ∏ c o s + ∏ s i n ( ∏ c o s ) ′ ) ( ∑ k x a y b z c ) + ( ∏ T r i s ( ∑ ( k x a y b z c ) ) ′ ) = ((\prod{sin})'\prod{cos} + \prod{sin}(\prod{cos})')(\sum{kx^ay^bz^c}) + (\prod{Tris}(\sum{(kx^ay^bz^c))')} =((sin)cos+sin(cos))(kxaybzc)+(Tris((kxaybzc)))
      3. 确定好架构后,我们发现,一共需要得到三样东西
        • ( ∏ s i n ) ′ (\prod{sin})' (sin)
        • ( ∏ c o s ) ′ (\prod{cos})' (cos)
        • ∑ ( k x a y b z c ) ′ \sum{(kx^ay^bz^c)'} (kxaybzc)
          那就非常简单了,我们举例来看:
          在这里插入图片描述同理cos列的求导,此外,对于基础monos的求导则更为简单,在此不作过多赘述。
          这样每一个term都能被求导完成,从而完成dx(poly)。
    1. 求导完成后,会返回一系列terms,把这些terms,化成一个exprFactor(解析完成的),加入到exprFactors列中,接下来就可以从容地应用上一次左右的架构了
  • 输出优化
    完全参照上次作业。

bug

  • 笔者三次作业的bug出现的高度相同,分别是正负号,和深克隆
    • 第一次作业出现的克隆问题是展开一个exprFactor,当他的power不为零时乘积展开的克隆出现了浅克隆,以及exprFactor前方的正负号没有进行记录。
    • 由于第三次作业在求导过程中需要大量的深克隆,笔者新增一个类叫做cloneTool。注意bigInteger也需要单独深克隆,用add(Zero)方法深克隆。
    • 第三次作业被hack到的一个点是没有考虑到-dx()这样,在求导符号前面有负号的情况,但因为笔者之前的正负号判断已经完善,所以只需要特判一次字符串。
  • 笔者因为对Python了解尚浅,所以没有用任何的评测机,就算是hack也只是下载了同组同学的文件,然后先尝试几个样例,然后静态分析代码。希望后续学习可以掌握评测机的使用TT

心得体会

好的架构是迭代完成作业的基础,虽然没有完全使用面向对象思想,但其实笔者的结构也足够接续迭代开发的可能性。笔者在这里非常感谢我的同班同学,在我打算第二次到第三次作业重构的时候及时制止了我,否则我很可能交不上第三次作业:)
第一单元的作业总体难度我认为呈中-上-下的难度变化趋势,虽然第一周我是真的觉得我不可能写出来这个作业了,但是从第四周回看我的作业历程,似乎也没有那么不可攻克。
我是个心态很差的人,因为专业课大课缓考两门(计组和离散2)和oo第一周就上强度的作业撞上,我几乎要崩溃。但非常感谢我的朋友们和于助教对我的鼓励,让我有信心能完成三次作业。笔者第一周,第二周每周都写了20+小时的代码,第三周写了5小时。非常感慨。
希望看到博客的同学加油再加油,我也再加油。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值