2022-OO-unit1
作者:互联网
2022-OO-unit1
一、简述
由于冬残奥会原因,我的第一单元作业大概延期了半个月才完成。并且完成期间处于隔离期,与同学、助教、老师讨论的次数几乎为零,所以我的架构可能与其他同学的架构差异度较大(因为没有很懂指导书中的递归下降)。我对第一单元作业的总结如下。
二、架构分析
第一单元的三次作业我分为两次完成,由于第三次作业的功能包含了第二次作业的功能,所以我在完成第一次作业之后直接开始了第三次作业的编写。所以我在此展示第一次作业和第三次作业的架构。
第一次作业
解析方式我使用了指导书中的递归下降方法,但由于本人可能没有完全理解递归下降的本质,所以写出的代码可能不是纯正的递归下降。
在第一次作业中,首先将输入的表达式通过Handle类进行简单的处理:删去空白符、处理冗余的正负号(如:++、-++、-+-)、加上必要的括号,如:将”x*-5“改为”x*(-5)“。
之后根据处理过的表达式建立Expr类,调用parseExpr方法,得到所有的项。并建立Simplify类的对象,用于化简最终表达式。之后对每个项调用parseTerm方法和calculate方法,得到各项的计算结果,将各项的结果利用Simlify类中的addIndexCoe方法存入Simplify对象中。
这时,所有的项的计算结果就全部存入Simplify对象中,调用Simplify类的merge方法、makeAnswer方法得到答案字符串,之后调用exchanLocation方法,进一步减小答案长度,比如将”-x+1“改为”1-x“。最后调用getAnswer方法得到最终字符串,并将其打印。
第三次作业
Method | CogC | ev(G) | iv(G) | v(G) |
---|---|---|---|---|
MainClass.main(String[]) | 2 | 1 | 3 | 3 |
calculate.Handle.Handle(String) | 0 | 1 | 1 | 1 |
calculate.Handle.Handle(String, HashMap<Character, DefineFunction>) | 0 | 1 | 1 | 1 |
calculate.Handle.addParentheses() | 7 | 1 | 4 | 5 |
calculate.Handle.deleteDefFunction() | 0 | 1 | 1 | 1 |
calculate.Handle.deleteFunction(char) | 3 | 2 | 3 | 4 |
calculate.Handle.deleteSum() | 3 | 2 | 3 | 4 |
calculate.Handle.deleteWhiteSpace() | 1 | 1 | 2 | 2 |
calculate.Handle.findFunction(String, int) | 1 | 1 | 1 | 2 |
calculate.Handle.findSum(String, int) | 1 | 1 | 1 | 2 |
calculate.Handle.getInput() | 0 | 1 | 1 | 1 |
calculate.Handle.handleInput() | 2 | 1 | 4 | 4 |
calculate.Handle.handleSymbols() | 0 | 1 | 1 | 1 |
calculate.IndexTri.IndexTri() | 0 | 1 | 1 | 1 |
calculate.IndexTri.IndexTri(BigInteger, HashMap<Triangle, BigInteger>) | 0 | 1 | 1 | 1 |
calculate.IndexTri.equals(Object) | 3 | 3 | 2 | 4 |
calculate.IndexTri.getIndex() | 0 | 1 | 1 | 1 |
calculate.IndexTri.getTriangle() | 0 | 1 | 1 | 1 |
calculate.IndexTri.hashCode() | 0 | 1 | 1 | 1 |
calculate.IndexTri.multi(IndexTri) | 0 | 1 | 1 | 1 |
calculate.IndexTri.multiTriangle(HashMap<Triangle, BigInteger>, HashMap<Triangle, BigInteger>) | 4 | 1 | 3 | 3 |
calculate.IndexTri.setIndex(BigInteger) | 0 | 1 | 1 | 1 |
calculate.IndexTri.setTriangle(HashMap<Triangle, BigInteger>) | 0 | 1 | 1 | 1 |
calculate.IndexTri.toString() | 9 | 2 | 8 | 9 |
calculate.Simplify.Simplify() | 0 | 1 | 1 | 1 |
calculate.Simplify.Simplify(ArrayList<HashMap<IndexTri, BigInteger>>) | 0 | 1 | 1 | 1 |
calculate.Simplify.Simplify(HashMap<IndexTri, BigInteger>) | 0 | 1 | 1 | 1 |
calculate.Simplify.addTermResult(HashMap<IndexTri, BigInteger>) | 0 | 1 | 1 | 1 |
calculate.Simplify.addTermResultUltra(HashMap<IndexTri, BigInteger>) | 4 | 1 | 3 | 3 |
calculate.Simplify.coeEqualMinusOne(IndexTri) | 2 | 2 | 1 | 2 |
calculate.Simplify.coeEqualOne(IndexTri) | 2 | 2 | 1 | 2 |
calculate.Simplify.coeGreatOne(IndexTri, BigInteger) | 2 | 2 | 1 | 2 |
calculate.Simplify.coeSmallMinusOne(IndexTri, BigInteger) | 2 | 2 | 2 | 2 |
calculate.Simplify.exchangeLocation() | 9 | 4 | 6 | 6 |
calculate.Simplify.getResultUltra() | 0 | 1 | 1 | 1 |
calculate.Simplify.makeAnswer() | 8 | 3 | 8 | 8 |
calculate.Simplify.mergeTermResults() | 5 | 2 | 3 | 4 |
calculate.Simplify.toString() | 0 | 1 | 1 | 1 |
expression.Cos.Cos(String) | 2 | 1 | 2 | 2 |
expression.Cos.equals(Object) | 2 | 3 | 1 | 3 |
expression.Cos.getFactorValue() | 0 | 1 | 1 | 1 |
expression.Cos.hashCode() | 0 | 1 | 1 | 1 |
expression.Cos.isHasCosZero() | 3 | 1 | 3 | 3 |
expression.Cos.isHasZeroCos(IndexTri, BigInteger) | 5 | 4 | 5 | 6 |
expression.Cos.isNeedParen(IndexTri, BigInteger) | 6 | 1 | 8 | 9 |
expression.Cos.isZero() | 0 | 1 | 1 | 1 |
expression.Cos.makeFactor() | 0 | 1 | 1 | 1 |
expression.Cos.print() | 0 | 1 | 1 | 1 |
expression.Cos.toString() | 11 | 5 | 7 | 8 |
expression.DefineFunction.DefineFunction(String) | 0 | 1 | 1 | 1 |
expression.DefineFunction.getInput() | 0 | 1 | 1 | 1 |
expression.DefineFunction.getVar() | 3 | 1 | 3 | 3 |
expression.DefineFunction.print() | 0 | 1 | 1 | 1 |
expression.DefineFunction.setInput(String) | 0 | 1 | 1 | 1 |
expression.DefineFunction.toString(String) | 10 | 3 | 9 | 9 |
expression.Expr.Expr() | 0 | 1 | 1 | 1 |
expression.Expr.Expr(String) | 0 | 1 | 1 | 1 |
expression.Expr.addTerms(Term) | 0 | 1 | 1 | 1 |
expression.Expr.extractFirstTerm() | 3 | 1 | 4 | 4 |
expression.Expr.extractTerm(int) | 8 | 5 | 4 | 5 |
expression.Expr.findChar(String, char, char) | 4 | 3 | 3 | 4 |
expression.Expr.getExpr() | 0 | 1 | 1 | 1 |
expression.Expr.getTerms() | 0 | 1 | 1 | 1 |
expression.Expr.hasCorrectParentheses(String) | 5 | 1 | 4 | 4 |
expression.Expr.isPlusOrMines(char) | 1 | 1 | 1 | 2 |
expression.Expr.notStartWithPS() | 7 | 5 | 3 | 5 |
expression.Expr.parseExpr() | 1 | 1 | 2 | 2 |
expression.Expr.print() | 1 | 1 | 2 | 2 |
expression.Number.Number(String) | 0 | 1 | 1 | 1 |
expression.Number.getNumber() | 0 | 1 | 1 | 1 |
expression.Number.print() | 0 | 1 | 1 | 1 |
expression.Power.Power(String) | 4 | 1 | 3 | 3 |
expression.Power.getIndex() | 0 | 1 | 1 | 1 |
expression.Power.print() | 0 | 1 | 1 | 1 |
expression.Sin.Sin(String) | 2 | 1 | 2 | 2 |
expression.Sin.equals(Object) | 2 | 3 | 1 | 3 |
expression.Sin.getFactorValue() | 0 | 1 | 1 | 1 |
expression.Sin.hashCode() | 0 | 1 | 1 | 1 |
expression.Sin.isHasSinZero() | 3 | 1 | 3 | 3 |
expression.Sin.isHasZeroSin(IndexTri, BigInteger) | 5 | 4 | 5 | 6 |
expression.Sin.isNeedParen(IndexTri, BigInteger) | 6 | 1 | 8 | 9 |
expression.Sin.isZero() | 0 | 1 | 1 | 1 |
expression.Sin.makeFactor() | 2 | 1 | 2 | 2 |
expression.Sin.print() | 0 | 1 | 1 | 1 |
expression.Sin.toString() | 11 | 5 | 7 | 8 |
expression.Sum.Sum(String) | 0 | 1 | 1 | 1 |
expression.Sum.exchange(String, BigInteger) | 5 | 2 | 3 | 3 |
expression.Sum.getOutput() | 0 | 1 | 1 | 1 |
expression.Sum.makeOutput() | 3 | 2 | 3 | 4 |
expression.Sum.parse() | 1 | 1 | 2 | 2 |
expression.Sum.print() | 0 | 1 | 1 | 1 |
expression.Term.Term(String) | 0 | 1 | 1 | 1 |
expression.Term.addCos(String) | 6 | 4 | 2 | 4 |
expression.Term.addFactor(Factor) | 0 | 1 | 1 | 1 |
expression.Term.addFactor(String) | 15 | 1 | 11 | 11 |
expression.Term.addHashMap(HashMap<IndexTri, BigInteger>, HashMap<IndexTri, BigInteger>) | 7 | 1 | 4 | 4 |
expression.Term.addIndexCoe(HashMap<IndexTri, BigInteger>, IndexTri, BigInteger) | 2 | 1 | 2 | 2 |
expression.Term.addNumberNegativeOne() | 0 | 1 | 1 | 1 |
expression.Term.addPower(String) | 8 | 2 | 7 | 7 |
expression.Term.addSin(String) | 6 | 4 | 4 | 4 |
expression.Term.calculate() | 2 | 1 | 2 | 2 |
expression.Term.deleteExprPowerTerm() | 35 | 1 | 8 | 9 |
expression.Term.deleteFactorExprParen() | 8 | 3 | 6 | 7 |
expression.Term.divideFactor() | 5 | 1 | 5 | 5 |
expression.Term.exprCalculate() | 4 | 1 | 3 | 3 |
expression.Term.extractFactor(int) | 9 | 4 | 5 | 8 |
expression.Term.findTriangle(HashMap<Triangle, BigInteger>, Triangle) | 3 | 1 | 2 | 3 |
expression.Term.getFactors() | 0 | 1 | 1 | 1 |
expression.Term.getResultUltra() | 0 | 1 | 1 | 1 |
expression.Term.getTerm() | 0 | 1 | 1 | 1 |
expression.Term.hasCorrectParentheses(String) | 4 | 1 | 4 | 4 |
expression.Term.hasExpr() | 3 | 3 | 1 | 3 |
expression.Term.hasTriangle(Set |
3 | 3 | 2 | 3 |
expression.Term.makeExprMap(Expr) | 1 | 1 | 2 | 2 |
expression.Term.multiHashMap(HashMap<IndexTri, BigInteger>, HashMap<IndexTri, BigInteger>) | 4 | 1 | 3 | 3 |
expression.Term.multiIndexTriCoe(HashMap<IndexTri, BigInteger>, IndexTri, BigInteger) | 1 | 1 | 2 | 2 |
expression.Term.multiNotExpr() | 4 | 1 | 4 | 4 |
expression.Term.multiTriangle(ArrayList |
10 | 4 | 6 | 7 |
expression.Term.parseTerm() | 1 | 1 | 2 | 2 |
Total | 327.0 | 185.0 | 297.0 | 337.0 |
Average | 2.7478991596638656 | 1.5546218487394958 | 2.495798319327731 | 2.831932773109244 |
由于第一次作业意外地实现了对嵌套括号的处理(第三部分会讲,详情请见第三部分),所以第三次作业中我的重点放在了自定义函数的处理、三角函数的处理。
首先将输入的自定义函数封装为DefineFunction对象,之后在建立的Handle对象中将所有的空白符删去、将所有的自定义函数(包含sum)全部替换成为不带函数的表达式、处理所有的冗余正负号、加上必要的括号,并根据处理后的表达式建立Expr对象。
之后的架构与第一次作业相同,先解析出每个项,之后对每个项进行计算。将每个项的计算结果存入Simplify中,进行合并与化简,最终输出最后结果。
方法度量分析
Term类中的deleteExprPower方法是CogC值最高的方法,这个方法是我写的最失败的一个方法。因为前期没有对各种情况进行合理的分类,导致代码结构很乱,产生了多个if的嵌套,认知性很差。
Sin类和Cos类的toString方法是ev(G)值最高的方法。这个方法涉及三角函数的表达,if和for互相嵌套,导致非结构化程度较高,但是由于能力有限,未能找到合理的解决办法。
Term类的addFactor(String)方法是iv(G)值最高的方法。这个方法会根据输入构造不同的因子,所以会调用所有因子的构造方法,必然导致模块设计复杂度高,即模块耦合度高,本人认为很难避免。
Term类的addFactor(String)方法是v(G)值最高的方法,在这个方法中需要判断输入字符串是否符合各个因子的特征,所以if后接了数个else,导致结构复杂。
三、解析过程
- 从开头遍历,如果遇到的符号不是加号或减号,便继续前进;如果遇到加减号,便看这个加减号与之前的加减号截出的字符串是否满足正确的括号匹配(用栈判断括号是否正确匹配),如果满足,则这个截出的字符串便是一个项;如果不满足正确的括号匹配,则继续遍历。直到遇到满足条件的加减号或者遍历结束。
- 在对每个项进行处理时,与处理表达式的过程相似,从开头遍历,以乘号为标志,看两个乘号之间的表达式是否满足正确的括号匹配,如果满足,则这两个乘号之间的表达式为一个因子,如果不满足,则继续向前遍历,知道遇到满足条件的乘号或者遍历结束。
(注:正是由于前两步一直是以正确的括号匹配为标准来判断是否能找出一个正确的项或因子,所以我在第一次作业中便实现了嵌套括号的处理) - 在处理每个项的因子时,如果这个因子满足正则表达式"[+-]?sin\\(.*\\)",则这个因子为正弦函数;如果这个因子满足正则表达式"[+-]?cos\\(.*\\)",则这个因子为余弦函数;如果这个因子以括号开头,则这个因子为表达式;如果满足正则表达式"[+-]?[0-9]+",则这个因子为数字;若上述情况都不满足,则该因子为幂函数。
四、计算过程
第一次作业的计算过程
- 在对每个项进行计算时,首先判断该项中是否含有表达式因子。
- 如果有表达式因子,则将该项的因子组分为表达式因子组和非表达式因子组,对两个因子组分别计算。在计算表达式因子组时,对每个表达式因子建立Expr对象,依次调用parseExpr方法,之后对这个Expr对象的各个项进行计算(其实这里进行了递归),最终得到表达式因子组的计算结果。之后再得到非表达式因子组的计算结果(这个由于只含数字与极简的幂函数,如:x**3,比较简单,便不再详细介绍)。最终将两个因子组的结果进行合并。
- 如果没有表达式因子,那么说明该项只含数字与简单的幂函数,上段中已介绍过,这里不再赘述。
第三次作业的计算过程
- 在对每个项进行计算时,首先对所有因子分组,分为表达式因子组和三角函数因子组。
- 如果表达式因子组非空,则先对表达式因子组进行计算:为每个表达式建立Expr对象,之后调用parseExpr方法,对每个项调用calculate方法(其实这里也进行了递归),最终得到表达式因子组的计算结果。
- 之后计算三角函数因子组。这里和多项式乘法相同类似,如果函数名相同且函数内容相同,则该项次数加一,最终得到三角函数因子组的计算结果。
- 最后对所有因子中的数字与幂函数进行相乘,再把表达式因子组与三角函数因子组的结果相乘,得到最终结果。
五、结果存储
第一次作业
第一次作业只涉及多项式,所以只需要记录每一项的次数和系数即可。在我的作业中,我将次数和指数都设置为BigInteger(万一之后次数也会非常大呢)。每个多项式的项由指数和系数构成,那么由<BigInteger, BigInteger>即可表示一个项,用HashMap<BigInteger, BigInteger>即可表示一个多项式。
每个项会产生一个HashMap<BigInteger, BigInteger>,那么在Simplify中建立一个数据结构ArrayList<HashMapBigInteger, BigInteger>用来存储每个项的结果。在进行计算和化简之后用一个HashMap<BigInteger, BigInteger>即可表达最终结果。
第三次作业
第二次作业涉及三角函数与多项式,自然在存储数据的时候不能使用HashMap<BigInteger, BigInteger>来储存。在第三次作业中吗,结果的通项应该为:幂函数部分、三角函数部分、系数部分。那么可以将它分为两个部分,将幂函数与三角函数看为一个整体,封装为IndexTri类,将系数看为另一部分。这样,我们便可以用<IndexTri, BigInteger>来表示最终结果的通项。其中IndexTri中包含了幂函数的指数和三角函数部分。
每个项的计算结果均可由一个HashMap<IndexTri, BigInteger>表示,在Simplify中建立数据结构ArrayList<HashMap<IndexTri, BigInteger>>用来存储每个项的计算结果。在进行计算和化简之后用一个HashMap<IndexTri, BigInteger>即可表达最终结果。
六、化简过程
第一次作业
第一次作业的化简比较简单,因为只有多项式。这样的话将指数相同的项合并即可,这个难度不大。最终在将HashMap<BigInteger, BigInteger>表达时,需要注意两个点:第一个项尽量不是负项,即尽量不用符号开头,如果所有项都是负项的话,就只能负号开头了;x**2要改成x*x(完全是为了减少长度)。
第三次作业
第三次作业的化简复杂了不少。在第一单元的基础上,我只实现了sin(0)和cos(0)的化简,Sin和Cos类中的boolean型成员变量zero便是判断函数内容的值是否为0。对于sin(0)、sin(x-x)等变量,直接将所在的IndexTri清零;对于cos(0)、cos(x-x)等变量,直接将所在的IndexTri置1。
对于平方和化简、二倍角化简、奇偶性化简等化简方法,本人由于时间原因与能力原因没有实现(因为电梯作业马上要发布了)。
七、程序bug
在第一单元作业中,我的程序产生的bug非常多,很多bug都是因为对各种情况考虑不充分产生。
- --+这种冗余符号的处理。
- 对-x**4化简时将负号处理错误导致得到(-x)*(-x)*(-x)*(-x)
- 输出时未加必要括号,直接输出了sin(x-x)而不是sin((x-x))
除此之外还有很多bug,我认为产生这些bug的原因有两方面:
- 没有详细地读指导书,对指导书中专门提到的情况没有特殊处理
- 最初开始时并没有一个很清晰的架构,为了赶ddl而匆匆开始,边写边改,使得在后续过程中出现了很多粗心的bug。
八、心得体会
- 第一单元作业是我进入大学以来第一次完全独立自主地、从零开始的超过一千七百行代码的作业。从最初的迷茫到最后完成,既是学习的过程,也是历练的过程,更是提升自信心的过程。
- 由于服务冬残奥会,自己落下了很多作业与实验。特地感谢助教为我多次延期,让我有足够的时间完成第一单元的作业,感谢助教团队。
标签:OO,Term,calculate,IndexTri,因子,2022,unit1,expression,String 来源: https://www.cnblogs.com/yjzhao-buaa/p/16128148.html