275
社区成员
发帖
与我相关
我的任务
分享
预处理init,处理多余的符号和空格,保证只会出现最多一个符号
递归下降
词法分析Lexer,分析出要处理的符号
语法分析Parser,根据符号分割,分析出Expr,Term,Factor。分成三部分进行处理——parseExpr, parseTerm, parseFactor;parseExpr用加号进行处理,进入解析项,parseTerm用乘号进行处理,进入解析因子。
文法层次设置
表达式主要包含三部分——Expr,Term,Factor,而Factor又有三种——幂函数,常数因子和表达式因子,我们对他们进行分别建类。其中Expr类中使用ArrayList来容纳该表达式中含有的Term,Term类中使用ArrayList来容纳该项中含有的Factor。
表达式展开
可以发现最后的多项式具有一个统一的形式,我们可以基于这个形式建立一个Unit类,再建立一个Poly,Poly类有一个ArrayList容器,用来容纳Unit,此外还有addPoly(),mulPoly()和powPoly()等方法来实现多项式的运算。最后只需要实现Poly类里的tostring就可以顺利进行展开化简
当然在这个过程中我们还要运用递归下降的方法,自底向上的用toPoly让每一个都变到Poly项
hw1涉及到的优化点不是很多,只需要特殊考虑指数系数为0的特殊情况即可。

可以看出我的架构没有发生太大的改变,只是增添了新的功能。
三角函数类
新建了一个sinFactor类和cosFactor类,包含factor:三角函数括号内的因子和exp:三角函数的指数部分
parser类设置parserSinCosFactor()方法,对三角函数括号内的因子进行解析,然后解析该三角函数的指数,解析因子我直接使用了parseExpr方法,可以处理更多的可能性
递推函数
在处理递推函数时,我选择增加Definer进行处理,FunFactor进行存储
Definer中我进行了字符串替换,增加递归的替换方法,等待被调用
parser类设置parserFunFactor()方法,读到f就进入Definer进行替换,最后返回一个字符串,在进行递归下降处理为Expr
表达式展开
多项式的基本单元发生了变化从ax^b 到现在的 ax^b(sin)^m(cos)^n
优化
在三角函数的化简方面,我尝试重写equal方法,比较是否相等,还写了一个比较是否是相反数的方法,最后如果是cos和sin的偶数次幂,我就比较它是否equal或者反向equal,如果是sin的奇数次幂,我比较他是否是equal的。以上的优化并未对我的正确性产生什么影响。因为该实现方法并没有对总体的架构产生影响,也不容易产生一些错误。
以上是基本架构,在后期修bug和优化代码时,我试了另外两种种递归函数的方法。第二种方法里不需要对字符串进行过分的解析。只需要替换掉递推函数的序号,然后返回递推函数替换掉序号的字符串,再次进行递归下降。在第三种方法下,有递推函数,先把f0到f5解析出来,之后再遇到f就可以直接替换就可以。不过三种方法最后的性能差距不大。

在Parser类中增加parseDerFactor方法,parseFactor中调用
然后仍然采用递归下降的思路,层层求导,Expr实现加法,Term中实现乘法法则和链式法则
新建了一个工具类NomalFunDefiner对于自定义普通函数进行处理,思路其实和f{0}很相似
parser类中设置了一个parseNormalFun()方法,先解析函数名,然后解析所有的实参


仅展现出数值高的部分
每个方法的规模与控制分支数目
v(G)(圈复杂度)间接评估,数值越高逻辑越复杂。Definer.calFunc(FunFacter)(v(G)=8)Unit.sinCosEqualHash(...)(v(G)=20)Poly.mulPoly(Poly)(v(G)=13)v(G) 直接反映分支数目。v(G)=20 表示可能存在嵌套循环或大量条件分支。类的总代码规模
通过 WMC(加权方法复杂度)体现:
Poly(WMC=53)Unit(WMC=50)Definer(WMC=29)Number(WMC=5)Var(WMC=5)OCavg(平均操作复杂度):
1.00)表示高内聚(如 Number、Var)。Poly.OCavg=4.42)表明类职责分散,内聚性较低。耦合性
Definer 与 FunFacter 交互(方法参数)。Poly 和 Unit(涉及复杂数据操作,如 addPoly、mulPoly)。就架构而言,我的思路是很清晰的,也具有很好的拓展性,可以继续加很多东西。
比如加一些指对函数,一些定义函数,连续求积,连续求和等。
按照我的架构而言,仅仅只需要在其中加入因子,修改一些计算逻辑,修改基本项即可
Poly(WMC=53)和 Unit(WMC=50)逻辑过于复杂;太多方法集中在Poly类里了,复杂度过高
Definer.calFunc(v(G)=8)和 Unit.sinCosEqualHash(v(G)=20)需重构优化逻辑
仍然会出现面向过程的问题
在三角函数化简的方面仍然有做的不足的地方,需要加以改进
在实现处理-号时,把它当作了Term的一个属性,这个处理并不是很好,也导致了后面bug的产生
在第一次代码时我并未产生bug
在第二次代码时我出现的bug集中在
没有处理 sin(0)^0因为之前处理的时候只要系数为0就输出0,没有考虑到这条
在递推函数替换字符串的时候,识别x,y进行替换,可能会出现重复替换的情况,修改替换顺序即可
或者有一种更好的方法是先把x,y换成i,j这样无关的变量
对题目要求识别不清晰,没有考虑到三角函数内的括号层数,在优化时对sin(2*x)只输出了一层
在第三次代码时我的bug是
由于我之前的Term项里有sign属性,但是在我clone的时候没有clone这个属性,导致出现问题,符号错误
由于自定义函数在写的时候没有思考清楚,增加了不必要的字符串处理,反而写出来 bug
测试策略是先输入一些自己犯过的bug,看看是否遇到同样的bug
然后针对于一些边界数据进行测试
看一下别人的代码,查看他容易出问题那部分的逻辑,比如递推函数等
不过仍然需要自己学习一下搭评测机,如果有评测机就可以更快的针对出错误点了
在第一单元的学习中我投入了大量的时间,但由于自己的测试不够,细心不够,导致自己的强测成绩不够好,之后需要改掉自己的缺点。不过我确实提升了自己的编码能力,对递归下降的理解更加深入了,也渐渐理解了面向对象的好处。认识到了一些性能上的优化远没有正确性重要。
不弃微末,久久为功。在为没有被发现的bug而难过时,我也确实感受到了自己的进步。而学习可能就是这样的过程,虽然我可能现在做的不是很好,但是我确实在向前行走,相信我的代码会越写越好。
我认为递推函数和自定义的函数实现很类似;可以把自定义普通函数换成一个其他的计算,或者把他们调换一下顺序。还有就是如果有教搭评测机的教程就更加好了.