382
社区成员
在第一次作业中,我尝试使用某种“统一”的,单一的表达方式在不同的运算处理中传输,最终选定的表达方式是Array List<Hashmap<Integer,BigInteger。Integer储存字母因子的ASC码,或者为0,表示这一因子为系数。BigInteger储存字母因子的次数或者是系数的大小,组合为Hashmap构成一个项,多个项以ArrayList储存构成表达式。用Operater接口来实现各个运算的具体方法。Operater中必须要有以运算符号为分割两端的表达式的具体结果。
在对表达式的解析上,我认为词法解析单独写一类没有特别的意义,找到各个运算符的具体位置即可。对于表达式解析采用递归下降的方法,首先将所有以在括号外的加减为分割多项式,进一步以括号外乘法为界限分割多项式,然后以指数运算符分割,再以加减分隔,最后以乘法分割,最终达到一个要么是数字,要么是字母的分割结果。
Method | CogC | ev(G) | iv(G) | v(G) |
Add.Add(Operator, Operator) | 0 | 1 | 1 | 1 |
Add.check(HashMap<Integer, BigInteger>, HashMap<Integer, BigInteger>) | 14 | 7 | 7 | 11 |
Add.getResult() | 9 | 4 | 5 | 5 |
Exp.Exp(Operator, Operator) | 0 | 1 | 1 | 1 |
Exp.getResult() | 36 | 4 | 16 | 16 |
MainClass.main(String[]) | 16 | 1 | 7 | 7 |
Mul.Mul(Operator, Operator) | 0 | 1 | 1 | 1 |
Mul.getResult() | 20 | 1 | 10 | 10 |
Nom.Nom(String) | 3 | 1 | 3 | 3 |
Nom.getResult() | 0 | 1 | 1 | 1 |
Operator.Operator(Operator, Operator) | 0 | 1 | 1 | 1 |
Operator.getLeft() | 0 | 1 | 1 | 1 |
Operator.getResult() | 0 | 1 | 1 | 1 |
Operator.getRight() | 0 | 1 | 1 | 1 |
Parser.Parser() | 0 | 1 | 1 | 1 |
Parser.findAddOrSub1(String) | 11 | 4 | 3 | 7 |
Parser.findAddOrSub2(String) | 4 | 3 | 3 | 4 |
Parser.findExp(String) | 4 | 3 | 3 | 4 |
Parser.findMul(String) | 11 | 4 | 4 | 8 |
Parser.findMul2(String) | 4 | 3 | 4 | 5 |
Parser.parse(String) | 3 | 1 | 3 | 3 |
Parser.parse1(String) | 7 | 3 | 3 | 3 |
Parser.parse2(String) | 3 | 2 | 2 | 2 |
Parser.parse3(String) | 3 | 2 | 2 | 2 |
Parser.parse4(String) | 7 | 3 | 3 | 3 |
Parser.parse5(String) | 3 | 2 | 2 | 2 |
Sub.Sub(Operator, Operator) | 0 | 1 | 1 | 1 |
Sub.check(HashMap<Integer, BigInteger>, HashMap<Integer, BigInteger>) | 14 | 7 | 7 | 11 |
Sub.getResult() | 10 | 4 | 6 | 6 |
Class | OCavg | OCmax | WMC | |
Add | 4.33 | 7 | 13 | |
Exp | 7.5 | 14 | 15 | |
MainClass | 7 | 7 | 7 | |
Mul | 4.5 | 8 | 9 | |
Nom | 2 | 3 | 4 | |
Operator | 1 | 1 | 4 | |
Parser | 3.08 | 6 | 37 | |
Sub | 4.67 | 7 | 14 | |
Package | v(G)avg | v(G)tot | ||
4.21 | 122 | |||
Module | v(G)avg | v(G)tot | ||
oohomework_2023_20377049_hw_1 | 4.21 | 122 | ||
Project | v(G)avg | v(G)tot | ||
project | 4.21 | 122 |
这样的构造并不能体现抽象和层次化,通过这样的大一统的方式来储存所有的表达式,表达式中不可能再储存表达式的,使得对于后期作业三角函数的储存变得几乎不可能实现,没有体现面向对象的思想。同时在具体的函数上,由于多次的对ArrayList和Hashmap的遍历,使得时间复杂度大量上升,可以轻而易举得出这个结构是不好的结构。在函数的运算上,为了克服深浅拷贝的问题,我每一次都新声明了一个变量,尽量通过改变和返回新的变量来避免对原容器内容的修改,创造了一些冗余的储存。
对于如何储存表达式、项、因子,我的第一次作业的储存结构完全不能迭代使用,故对这一部分进行了完全的重构,随之对于运算类进行了与之适配的小幅的重构,而语法解析的重构则几乎保留,改写相对容易。
在新的表达式储存容器,我采取的方式是:接口Factor implement四个类Expr(表达式)、Term(项)、Var(字母因子)、Tri(三角函数因子)。Factor接口要实现两个函数,get()函数返回Hashmap<Factor,Biginteger>,equal(Factor)函数返回两个factor是否相同的boolean。Expr的Hashmap<Factor,Biginteger>储存term的系数,term的Hashmap<Factor,Biginteger>储存因子到次数,Var的Hashmap<Factor,Biginteger>中,Factor为Term类用于标志此为字母因子,Biginteger储存字母因子的asc码,Tri的Hashmap<Factor,Biginteger>中,Factor为Expr类,储存三角函数内部的表达式,Big integer用来标识三角函数的sin/cos;对于每一个类中的equal()都要同时比较两个factor的Hashmap<Factor,Biginteger>的相同与否,也就是比较Hashmap<Factor,Biginteger>中的Factor是否相同,Biginteger是否相同将表达式进而一步步落到字母的比较,对于三角函数的内部expr的比较最终也会调用Expr中定义的expr最终达到统一。然后利用equal()来实现同类项的合并。
对于自定义函数,储存每个函数输入的表达式的f、g、h作为function类的symbol,对被解析的项调用的函数比较他们的symbol来确定调用的函数,同时在function类中储存字符替换后的String表达式,当具体函数调用时,利用String的replace方法将因子进行替换,然后再进行词法解析,带入原函数。
Method | CogC | ev(G) | iv(G) | v(G) |
Add.Add(Expr, Expr) | 0 | 1 | 1 | 1 |
Add.get() | 2 | 1 | 3 | 3 |
Exp.Exp(Expr, Expr) | 0 | 1 | 1 | 1 |
Exp.get() | 21 | 4 | 11 | 11 |
Expr.Expr() | 0 | 1 | 1 | 1 |
Expr.addTerm(Factor, BigInteger) | 4 | 3 | 4 | 4 |
Expr.equal(Factor) | 18 | 9 | 7 | 11 |
Expr.get() | 0 | 1 | 1 | 1 |
Expr.toString() | 3 | 1 | 3 | 3 |
Generate.Generate(String) | 3 | 1 | 3 | 3 |
MainClass.main(String[]) | 1 | 1 | 2 | 2 |
Mul.Mul(Expr, Expr) | 0 | 1 | 1 | 1 |
Mul.get() | 9 | 1 | 5 | 5 |
Parser.Parser(ArrayList<function>) | 0 | 1 | 1 | 1 |
Parser.findAddOrSub1(String) | 11 | 4 | 3 | 7 |
Parser.findExp(String) | 11 | 4 | 3 | 7 |
Parser.findMul(String) | 11 | 4 | 4 | 8 |
Parser.parse1(String) | 7 | 3 | 3 | 3 |
Parser.parse2(String) | 3 | 2 | 2 | 2 |
Parser.parse3(String) | 3 | 2 | 2 | 2 |
Parser.parse4(String) | 12 | 7 | 10 | 10 |
Sub.Sub(Expr, Expr) | 0 | 1 | 1 | 1 |
Sub.get() | 2 | 1 | 3 | 3 |
Term.Term() | 0 | 1 | 1 | 1 |
Term.addFactor(Factor, BigInteger) | 4 | 3 | 4 | 4 |
Term.equal(Factor) | 18 | 9 | 7 | 11 |
Term.get() | 0 | 1 | 1 | 1 |
Term.toString() | 3 | 1 | 3 | 3 |
Tri.Tri(Expr, String) | 2 | 1 | 2 | 2 |
Tri.equal(Factor) | 7 | 4 | 4 | 4 |
Tri.get() | 0 | 1 | 1 | 1 |
Tri.toString() | 5 | 1 | 4 | 4 |
Var.Var(Character) | 0 | 1 | 1 | 1 |
Var.equal(Factor) | 7 | 4 | 3 | 4 |
Var.get() | 0 | 1 | 1 | 1 |
Var.toString() | 0 | 1 | 1 | 1 |
function.findComa(String) | 3 | 1 | 3 | 3 |
function.function(String, Character) | 0 | 1 | 1 | 1 |
function.get(String, ArrayList<function>) | 1 | 1 | 2 | 2 |
function.getSymbol() | 0 | 1 | 1 | 1 |
generateFunction.findEaqual(String) | 3 | 3 | 2 | 3 |
generateFunction.generateFunction(String) | 0 | 1 | 1 | 1 |
generateFunction.get() | 0 | 1 | 1 | 1 |
Class | OCavg | OCmax | WMC | |
Add | 2 | 3 | 4 | |
Exp | 6 | 11 | 12 | |
Expr | 3.6 | 9 | 18 | |
Generate | 3 | 3 | 3 | |
MainClass | 2 | 2 | 2 | |
Mul | 3 | 5 | 6 | |
Parser | 4.25 | 8 | 34 | |
Sub | 2 | 3 | 4 | |
Term | 3.6 | 9 | 18 | |
Tri | 2.75 | 4 | 11 | |
Var | 1.75 | 4 | 7 | |
function | 1.75 | 3 | 7 | |
generateFunction | 1.67 | 3 | 5 | |
Package | v(G)avg | v(G)tot | ||
3.28 | 141 | |||
Module | v(G)avg | v(G)tot | ||
homework_2 | 3.28 | 141 | ||
Project | v(G)avg | v(G)tot | ||
project | 3.28 | 141 |
更新了架构使得三角函数的储存变得轻松,整体的层次得以体现,代码初步具有了面向对象的思想。对于自定义函数的具体储存和返回值总是通过字符串来进行,显得相对笨拙,但是较为直观,易于理解。在各个具体实现Factor的类中分层次实现equal()方法,使得运算和化简变得简单,实现这个代码也相比于不分层变得更加简单。
相对简单,新加入了一个Derive类来实现函数的求导,具体的实现也较为简单,故不赘述。
Method | CogC | ev(G) | iv(G) | v(G) |
Add.Add(Expr, Expr) | 0 | 1 | 1 | 1 |
Add.get() | 2 | 1 | 3 | 3 |
Derive.Derive(Expr, Character) | 38 | 1 | 14 | 14 |
Derive.get() | 0 | 1 | 1 | 1 |
Exp.Exp(Expr, Expr) | 0 | 1 | 1 | 1 |
Exp.get() | 21 | 4 | 11 | 11 |
Expr.Expr() | 0 | 1 | 1 | 1 |
Expr.addTerm(Factor, BigInteger) | 4 | 3 | 4 | 4 |
Expr.equal(Factor) | 20 | 9 | 9 | 13 |
Expr.get() | 0 | 1 | 1 | 1 |
Expr.toString() | 3 | 1 | 3 | 3 |
Function.Function(String, Character) | 0 | 1 | 1 | 1 |
Function.findComa(String) | 3 | 1 | 3 | 3 |
Function.get(String, ArrayList<Function>) | 1 | 1 | 2 | 2 |
Function.getSymbol() | 0 | 1 | 1 | 1 |
Generate.Generate(String) | 3 | 1 | 3 | 3 |
GenerateFunction.GenerateFunction(String) | 0 | 1 | 1 | 1 |
GenerateFunction.findEaqual(String) | 3 | 3 | 2 | 3 |
GenerateFunction.get() | 0 | 1 | 1 | 1 |
MainClass.findComa(String) | 3 | 1 | 3 | 3 |
MainClass.findEaqual(String) | 3 | 3 | 2 | 3 |
MainClass.funcClean(String, ArrayList<Function>) | 1 | 1 | 2 | 2 |
MainClass.main(String[]) | 1 | 1 | 2 | 2 |
Mul.Mul(Expr, Expr) | 0 | 1 | 1 | 1 |
Mul.get() | 9 | 1 | 5 | 5 |
Parser.Parser(ArrayList<Function>) | 0 | 1 | 1 | 1 |
Parser.findAddOrSub1(String) | 13 | 4 | 5 | 9 |
Parser.findExp(String) | 11 | 4 | 3 | 7 |
Parser.findMul(String) | 11 | 4 | 4 | 8 |
Parser.isNumber(String) | 3 | 3 | 2 | 3 |
Parser.parse1(String) | 7 | 3 | 3 | 3 |
Parser.parse2(String) | 3 | 2 | 2 | 2 |
Parser.parse3(String) | 3 | 2 | 2 | 2 |
Parser.parse4(String) | 16 | 9 | 15 | 15 |
Sub.Sub(Expr, Expr) | 0 | 1 | 1 | 1 |
Sub.get() | 2 | 1 | 3 | 3 |
Term.Term() | 0 | 1 | 1 | 1 |
Term.addFactor(Factor, BigInteger) | 4 | 3 | 4 | 4 |
Term.equal(Factor) | 18 | 9 | 7 | 11 |
Term.get() | 0 | 1 | 1 | 1 |
Term.toString() | 3 | 1 | 3 | 3 |
Tri.Tri(Expr, String) | 2 | 1 | 2 | 2 |
Tri.equal(Factor) | 7 | 4 | 4 | 4 |
Tri.get() | 0 | 1 | 1 | 1 |
Tri.toString() | 5 | 1 | 4 | 4 |
Var.Var(Character) | 0 | 1 | 1 | 1 |
Var.equal(Factor) | 7 | 4 | 3 | 4 |
Var.get() | 0 | 1 | 1 | 1 |
Var.toString() | 0 | 1 | 1 | 1 |
Class | OCavg | OCmax | WMC | |
Add | 2 | 3 | 4 | |
Derive | 6.5 | 12 | 13 | |
Exp | 6 | 11 | 12 | |
Expr | 3.6 | 9 | 18 | |
Function | 1.75 | 3 | 7 | |
Generate | 3 | 3 | 3 | |
GenerateFunction | 1.67 | 3 | 5 | |
MainClass | 2.5 | 3 | 10 | |
Mul | 3 | 5 | 6 | |
Parser | 4.33 | 10 | 39 | |
Sub | 2 | 3 | 4 | |
Term | 3.6 | 9 | 18 | |
Tri | 2.75 | 4 | 11 | |
Var | 1.75 | 4 | 7 | |
Package | v(G)avg | v(G)tot | ||
3.59 | 176 | |||
Module | v(G)avg | v(G)tot | ||
oohomework_2023_20377049_hw_3 | 3.59 | 176 | ||
Project | v(G)avg | v(G)tot | ||
project | 3.59 | 176 |
由于对于不同因子的求导,如三角函数因子和字母因子的求导方式并不同,但我只写了Derive类,在其中加入了很多if判断,使得此类成为一“巨类”,是需要后续改进的,可以考虑将derive分别写入不同的类中,使得层次更加分明,避免出现这样的“巨类”。
经过了这三次的迭代作业,有这样几个经验,首先是层次化和抽象很重要,不要尝试用大一统的方式去解决和表示所有的问题,简单的分层和抽象可以让计算机自己去处理复杂的数据结构中有关索引的部分。其次是在第一次的作业时,就要尽量去思考如何为之后的迭代做准备。一个好的架构远比具体写出代码重要得多。
由于对于不同因子的求导,如三角函数因子和字母因子的求导方式并不同,但我只写了Derive类,在其中加入了很多if判断,使得此类成为一“巨类”,是需要后续改进的,可以考虑将derive分别写入不同的类中,使得层次更加分明,避免出现这样的“巨类”。
可以通过重构来改进