BUAA OO 第一单元总结

#OO 第一单元总结


本文为OO第一单元总结,本单元主要任务是表达式的展开与化简。核心思想是递归下降法,主要分为预处理、解析、多项式生成、化简四个个核心步骤。三次作业增量迭代的要求如下

  • 第一次作业

    • 去括号
      • 一层括号
    • 多项式化简
  • 第二次作业

    • 括号嵌套
    • 自定义函数
      • 无递归定义,有递归调用
    • 新增三角函数因子
  • 第三次作业

    • 自定义函数

      • 递归声明与调用
    • 新增求导因子

      • 仅出现一次

一、程序结构

1.类图(第三次作业)

preprocess the input by the method"strHandler"
parse the input by the method"parseExpr"
print the result by the method"getPrint"
replace the input's functions with expr
Parse the factor(Expr/Term/Factor)by Lexer
contains
contains
turn to Poly from Factor by the method "getPoly()"
Main
+main()
StrHandler
+strHandler() : String
+parseFunc() : String
+funcHandle() : String
+findBracket() : int
+remZero() : String
+noSignNum() : String
+noBracket() : boolean
+isNum() : boolean
+isTurnNeg() : boolean
Parser
-Lexer lexer
+parseExpr() : Expr
+parseTerm() : Term
+parseFac() : Factor
+parseDer() : Deri
+parseSin() : Sin
+parseCos() : Cos
Poly
-int sign
-ArrayList<Mono> monos
+turnNeg() : void
+addPoly() : void
+addMono() : void
+multPoly() : Poly
+getPrint() : String
Func
-String content
-int sum
-HashMap<Integer, String> parameters
+getSum() : int
+funcStruct() : coid
+getContent() : String
Factor
-int sign
+getSign() : int
+setSign() : void
+getPoly() : Poly
+derivation() : Poly
Lexer
-String input
-int pos
-String curToken
+getNum String
+next() : void
+getCurToken() : String
Mono
-int sign
-BigInteger con
-BigInteger xin
-BigInteger yin
-BigInteger zin
-HashMap<String,BigInteger> sins
-HashMap<String,BigInteger> coss
+setMono() : void
+clearHash() : void
+turnNeg() : void
+addSame() : void
+mulMono() : Mono
+addTris() : void
+addSin() : void
+addCos() : void
+isSame() : boolean
+isSameFang() : boolean
+getPrint() : String
+printTri() : String
+compareTo() : int
Expr
-int sign
-ArrayList<Term> terms
+addTerm() : void
+getPoly() : Poly
+derivation() : Poly
Term
-int sign
-ArrayList<Factor> factors
+addFac void
+getPoly Poly
+derivation() : Poly
Cos
-int sign
-Factor parameter
-BigInteger index
-Poly selfPoly
-String paraStr
+setParameter void
+setIndex() : void
+getPoly() : Poly
+derivation() : Poly
Sin
-int sign
-Factor parameter
-BigInteger index
-Poly selfPoly
-String paraStr
+setParameter void
+setIndex() : void
+getPoly() : Poly
+derivation() : Poly
Num
-int sign
-BigInteger value
+getPoly() : Poly
+derivation() : Poly
Var
-String name
+getPoly() : Poly
+derivation() : Poly
Deri
-int sign
-String fac
-Expr expr
+setFac() : void
+setExp() : void
+getPoly() : Poly
+derivation() : Poly
Power
-Expr base
-BigInteger index
-Poly basePoly
+getPoly() : Poly
+derivation() : Poly

2.代码结构

2.1代码行数

Source FileTotal LinesSource Code LinesSource Code Line[%]Comment LinesComment Lines[%]Blank LinesBlank Lines[%]
Factor.java22170.772727272727272700.050.22727272727272727
Deri.java24190.791666666666666600.050.20833333333333334
Main.java28270.964285714285714300.010.03571428571428571
Num.java32270.8437500.050.15625
Expr.java39320.820512820512820500.070.1794871794871795
Var.java44390.886363636363636400.050.11363636363636363
Func.java45410.911111111111111100.040.08888888888888889
Term.java48420.87500.060.125
Power.java54470.870370370370370300.070.12962962962962962
Lexer.java66580.878787878787878800.080.12121212121212122
Poly.java77690.896103896103896100.080.1038961038961039
Cos.java98900.918367346938775500.080.08163265306122448
Sin.java102950.931372549019607900.070.06862745098039216
Parser.java1511400.927152317880794700.0110.0728476821192053
StrHandler.java2452280.930612244897959110.004081632653061225160.0653061224489796
Mono.java3152950.936507936507936500.0200.06349206349206349

###2.2方法

MethodCogCev(G)iv(G)v(G)
Cos.Cos()0111
Cos.derivation(String)5344
Cos.getIndex()0111
Cos.getPoly()8166
Cos.setIndex(String)0111
Cos.setParameter(Factor)4144
Deri.derivation(String)0111
Deri.getPoly()0111
Deri.setExp(Factor)0111
Deri.setFac(String)0111
Expr.Expr()0111
“Expr.addTerm(Term, int)”0111
Expr.derivation(String)2133
Expr.getPoly()2133
Factor.derivation(String)0111
Factor.getPoly()0111
Factor.getSign()0111
Factor.setSign(int)0111
“Func.funcStruct(String, HashMap<String, Func>)”2133
Func.getContent(String[])1122
Func.getSum()0111
Lexer.Lexer(String)0111
Lexer.getCurToken()0111
Lexer.getNum()2133
Lexer.getPos()0111
Lexer.isSign()4335
Lexer.next()9238
Main.main(String[])2133
Mono.Mono()0111
Mono.Mono(Mono)0111
“Mono.addCos(String, BigInteger)”2122
Mono.addSame(Mono)6177
“Mono.addSin(String, BigInteger)”2122
Mono.addTris(Mono)2133
Mono.clearHash()0111
Mono.compareTo(Mono)0111
“Mono.getPrint(int, int)”2832022
Mono.isFang(Mono)3491515
Mono.isSame(Mono)4324
Mono.isSameFang(Mono)2212
Mono.mulMono(Mono)8177
Mono.printTri(int)4711717
“Mono.setMono(BigInteger, BigInteger, BigInteger, BigInteger, int)”0111
Mono.turnNeg()0111
Num.Num(String)0111
Num.derivation(String)0111
Num.getPoly()0111
Parser.Parser(Lexer)0111
Parser.paresDer(int)0111
Parser.paresSin(int)1222
Parser.parseCos(int)1222
Parser.parseExpr()7145
Parser.parseFac()1581111
Parser.parseTerm()1122
Poly.Poly()0111
Poly.addMono(Mono)10556
Poly.addPoly(Poly)1122
Poly.getPrint()3123
Poly.mulPoly(Poly)3133
Poly.turnNeg()1122
“Power.Power(Factor, String)”0111
Power.derivation(String)4233
Power.getPoly()2223
Sin.Sin()0111
Sin.derivation(String)5344
Sin.getIndex()0111
Sin.getPoly()8166
Sin.setIndex(String)0111
Sin.setParameter(Factor)9166
StrHandler.findBracket(String)7515
“StrHandler.funcHandle(String, HashMap<String, Func>)”5135
StrHandler.isNum(String)5415
StrHandler.isTurnNeg(String)9119
StrHandler.noBracket(String)12219
StrHandler.noSign(String)3334
StrHandler.noSignNum(String)8438
StrHandler.noZero(String)3224
“StrHandler.parseFunc(String, HashMap<String, Func>)”12157
StrHandler.strHandler(String)17148
“StrHandler.strHandler(String, HashMap<String, Func>)”17148
Term.Term()0111
Term.addFac(Factor)0111
Term.derivation(String)7155
Term.getPoly()2133
Var.Var(String)0111
Var.derivation(String)2122
Var.getPoly()3144
Total359136247307
Average4.131.562.843.53

###2.3类

ClassOCavgOCmaxWMC
Cos2.83617
Deri1.0014
Expr2.0038
Factor1.0014
Func2.0036
Lexer2.50715
Main3.0033
Mono4.501772
Num1.0013
Parser3.00921
Poly2.83617
Power2.3337
Sin3.17619
StrHandler5.18757
Term2.50510
Var2.3347
Total270
Average3.105.1216.88

二、核心架构

1.表达式

Expr
Term_1
Term_2
Term_n
Expr
Power
Deri
Sin
Cos
Var
Num
Expr
index
Expr
var
Factor
index
Factor
index

2.多项式

getPoly
getPoly
getPoly
multPoly
multPoly
multPoly
Factors getPoly multPoly
Factors getPoly multPoly
Expr
Term_1
Term_2
Term_n
Factor_1
Factor_2
Factor_n
Poly1
Poly2
Polyn
newPoly1
newPoly2
newPolyn
resultPoly

3.数学公式

r e s u l t P o l y = ∑ i = 0 n ∏ j = 0 m f a c t o r P o l y resultPoly = \sum_{i=0}^n \prod_{j=0}^m factorPoly resultPoly=i=0nj=0mfactorPoly

4.架构设计体验

第一次作业

​ 第一次作业比较简单,但由于考虑到之后的迭代开发,还是选择了递归下降,此时的代码可以处理括号嵌套的表达式。预处理包括:去除多余的正负号仅保留必要的符号、去除空白符和制表符、将**替换为^;词法语法解析的整体思路参考了练习作业提供的代码;化简在计算的过程中进行,Mono的标准形式为 Mono = axiyjzk,在单项式计算的时候采用深克隆

第二次作业

​ 第二次迭代增加了括号嵌套、自定义函数、三角函数因子。递归下降已经解决括号嵌套;对于自定义函数将其放到预处理中,也用递归下降先对自定义函数进行表达式化简,之后替换;在Mono中添加两个HashMap<String, index>分别记录三角函数的参数与指数,Mono的标准形式变为: M o n o = a x i ∗ y j ∗ z k ∏ i = 0 s i n ∏ i = 0 c o s Mono = ax^{i}*y^{j}*z^{k} \prod_{i=0} sin \prod_{i=0} cos Mono=axiyjzki=0sini=0cos。判断同列项(除了常数)去掉常数项后的字符串比较,为了保证sin(x+y)和sin(y+x)能够化简,在Poly的getPrint方法中,需要先对mono实现comparable接口重写比较方法。

第三次作业

​ 第三次迭代增加了自定义函数的递归调用、求导因子。自定义函数只需要在预处理的过程中像处理第二次表达式的方式处理即可;求导因子我们就当做新加因子,在表达式getPoly的时候处理,利用求导法则分别写出Expr、Term、其他因子的求导方法即可。

​ 由于第二次优化没有做多少,所以第三次最主要是两个优化,sin(y-x)+sin(x-y)和sin2+cos2。第一个比较好做,只需要在打印三角函数参数的时候依据正负号的数量和字符串比较来实现;第二个优化类似同列项判断,在Mono相加的时候遍历两个三角函数HashMap,判断另一个Mono中去掉相应的项之后的是否为同类项。此时便会出现新情况,例如:sin(x)*cos(x)+sin(x)3*cos(x)+cos(x)3*sin(x) 化简时出现新的同类项,对此我的做法是递归化简(乱起的名),以上述为例,先将后两项相加得到Mono:sin(x)cos(x),之后在Poly中删除刚刚化简得到的Mono,再将该Mono加入Poly中,发现同类项合并得到2sin(x)cos(x), 重复上述过程,删除2sin(x)*cos(x),再加到Poly中发现没有同类项,到此合并完成。

5.架构的优缺点

  • 优点

    • 求导因子,在求导因子生成多项式的时候再处理,可以复用之前的Poly相乘和相加的方法,且不会涉及深浅克隆问题
    • 三角函数存储方式为String,这样优点很明显,比如仅需要调用一次内层因子的打印函数
    • 边计算边化简,递归化简会比单独写一个化简函数方便,也更符合程序的流程
    • 可以处理求导因子的嵌套
  • 缺点

    • 对于自定义函数应该也当做因子处理,在解析的过程中替换,而不是在预处理中替换
    • 由于父类Factor拥有属性sign,但是在解析中真正有正负的只有Num和Term,其他的都默认为符号为1。在我的架构中埋下了隐患,这会在下面谈到

三、Bug

  • 第一次
    • 互测竟然没有挨刀,在系数为1的时候,特判条件太多,造成漏洞,1 * y * z输出yz
    • 0-x+x没有输出,这是因为-x+x合并完之后产生新的同类项,但是这个在互测和强测都没有测出来,自己也没注意到
  • 第二次
    • 1-x+x,哎,第一次作业埋的雷
    • sin(0) ** 0=0 在判断的时候先判断了sin参数是否为0
    • x**21 输出为x* * x1 直接对Mono输出的字符串直接进行替换
  • 第三次
    • dx(sin((-x))) 输出cos(x) 承接上文我的架构,由于我的sin因子里有Factor属性,Poly属性(Factor生成),在提负号到外面的时候只改变了Poly的符号(将所有Mono变号),但是没有把Factor变号。就算变号,由于(-x)是表达式因子,而在我的架构中表达式默认符号为正
  • 总结出现的bug
    • if特判条件,能否把所有的情况都考虑到,是否会漏到一些情况,应该优点判断那些情况
    • 直接对字符串处理是一件愚蠢至极的方法
    • 迭代产生的bug,大多数都是复用之前的方法导致错误

四、Hack策略

列举一些hack成功的例子

  • 边界条件

    • sin((-x)) --> sin(-x)

    • 1
      f(x)=cos(cos(cos(cos(x))))
      sin(sin(cos(cos(cos(cos(cos(cos(dx(f(x)))))))))) --> TLE                 利用cost条件实现TLE
      
  • 求导因子出现的位置,对特殊的因子求导

  • 1
    f(x,y) = ((+x))**2+y
    -dx(f(y,0))+y
    
  • 2
    f(x,y,z)=x-(y+z)
    g(x,z,y)=-dz((y-z)**2)
    -(f(0,-1,+1)-g(x**+0,x**+2,x**01))
    
  • 2
    f(x) = sin(cos(x))
    g(y ) = dy(f(y))
    g(y)
    

五、心得体会

​ 在第一次和第二次我几乎都没怎么做测试,第三次测试也只是把第二次数据改了改添加了求导因子,然后和室友python对拍,结果就是三次作业都有bug,下周说什么也得把评测机写出来。在写代码的时候尽量保证程序正义性,再结合随机测试数据和评测机才是正道!!

​ 复用之前的方法很容易出bug,接口的实现尤为重要,对于每个方法都需要清楚知道输入限制及方法的作用,迭代之后是否还能接着用。慢工出细活,写OO还是得抽出连续大量的时间,且要长时间专注。递归下降确实好用,但就是感觉缺少了一点面向对象的思想,第一单元感觉就像是数据结构哈哈哈哈。感觉评测没有上学期的OOpre覆盖性强,一个点就好几千上万条数据,bug还得靠互测。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值