OO | Unit1
第一次作业
程序架构
最初的设想是用
Expr->Term->Factor
的架构,但是由于刚刚接触 Java,还不懂接口等方法,不会处理表达式因子,所以直接把Factor
看成了一个项,每个Factor
都是a*x^n
的形式。我在
Factor
里分别创建了symbol
指示这一项的正负号,index
指示幂次,variable
指示变量(在本单元作业中是只有 x,当时考虑可拓展性加了variable
,在第二次作业的迭代中删了),constant
指示系数于是,在这样的的架构下,最终输出的就是多个
Factor
相加的形式,也就是Expr
。这样一来Term
的设计就显得很多余,实际上Term
也确实在输出时没有起到作用,Term
在我的架构里很像辅助Expr
乘法计算的一个中间量,我们把Term
也看作是一个表达式,每读取一个Term
就进行一次Term*Term
,处理完这一级全部的乘法之后就返回上一级,在返回前,Term
已经是多个Factor
相加的表达式,把Term
里的所有Factor
都加到Expr
里,再合并同类项就可以完成拆括号。(实际上可以给Term
和Factor
换个名字,会方便理解一点)
Processing
完成了字符串的预处理和后处理
预处理:
- 删除空格和制表符
- 删除前导零
- 将连续的加减号(最多三个)替换为单个加减号
- 将
*+
、^+
、(+
的+
删除 - 在每个左括号前添加
1*
,确保括号前有乘法因子 - 如果字符串以加号开始,则移除它
后处理(在toString
中的处理不太好,所以做了后处理)
- 将连续的加减号替换为单个加减号
- 移除
+0
的项
Lexer
沿用了training
中的Lexer
模块,进行字符串解析,解析出 数字字符串 字母字符串 符号字符串
Parser
采用了递归下降的写法,其架构如下
public Expr parseExpr() { |
需要说明的是,这里parseFactor
的返回值是Term类
。这是由于我在这里进行了表达式因子的幂运算,返回的是ArrayList<Factor>
,我又不希望再在Factor
里加入更繁琐的Expr
或Term
,所以如果处理的是变量因子
或常数因子
,返回的Term
size==1
,这样的设计可以使结构更加简单。
Expr
表达式类
-
包含一个属性
ArrayList<Factor>
-
实现了
addTerm
、addFactor
、simplifyExpr
的方法
addTerm
:把Term
中所有的Factor
都通过调用addFactor
加到Expr
中
addFactor
:把Factor
加到Expr
中
simplifyExpr
:化简表达式(合并同类项),比较每个Factor
中x
的幂次是否相同,相同的就系数相加,不同的就添加一个新的Factor
Term
乘法计算的表达式
- 包含一个属性
ArrayList<Factor>
- 实现了
multiply
、pow
、addAll
的方法
multiply
:乘法运算,计算表达式 Term 和表达式 Term 相乘得到的新表达式
pow
:计算 Term 自己的幂次运算,即将乘法运算进行 index 次
addAll
:把parseFactor
得到的Term
中的所有Factor
,全都加到当前的Term
中
Factor
项
-
包含四个属性,
symbol
:这一项的正负号,index
:幂次,variable
:变量,constant
:系数 -
主要实现了
mergeFactor
的方法
mergeFactor
:把两个Factor
合并,系数相加,幂次不变,符号和计算后的系数相同。
复杂度分析
Method | CogC | ev(G) | iv(G) | v(G) |
---|---|---|---|---|
expr.Expr.addFactor(Factor) | 0.0 | 1.0 | 1.0 | 1.0 |
expr.Expr.addTerm(Term) | 0.0 | 1.0 | 1.0 | 1.0 |
expr.Expr.Expr() | 0.0 | 1.0 | 1.0 | 1.0 |
expr.Expr.getFactors() | 0.0 | 1.0 | 1.0 | 1.0 |
expr.Expr.simplifyExpr(Expr) | 4.0 | 1.0 | 3.0 | 3.0 |
expr.Expr.toString() | 4.0 | 2.0 | 3.0 | 3.0 |
expr.Factor.Factor(int, int, String, BigInteger) | 0.0 | 1.0 | 1.0 | 1.0 |
expr.Factor.getConstant() | 0.0 | 1.0 | 1.0 | 1.0 |
expr.Factor.getIndex() | 0.0 | 1.0 | 1.0 | 1.0 |
expr.Factor.getSymbol() | 0.0 | 1.0 | 1.0 | 1.0 |
expr.Factor.getVariable() | 0.0 | 1.0 | 1.0 | 1.0 |
expr.Factor.mergeFactor(Factor) | 3.0 | 1.0 | 2.0 | 3.0 |
expr.Factor.toString() | 17.0 | 2.0 | 10.0 | 11.0 |
expr.Term.add(Factor) | 0.0 | 1.0 | 1.0 | 1.0 |
expr.Term.addAll(Term) | 0.0 | 1.0 | 1.0 | 1.0 |
expr.Term.addFactor(Factor) | 0.0 | 1.0 | 1.0 | 1.0 |
expr.Term.getFactors() | 0.0 | 1.0 | 1.0 | 1.0 |
expr.Term.multiply(Term) | 7.0 | 1.0 | 4.0 | 5.0 |
expr.Term.pow(Expr, Integer) | 6.0 | 1.0 | 6.0 | 6.0 |
expr.Term.size() | 0.0 | 1.0 | 1.0 | 1.0 |
expr.Term.Term() | 0.0 | 1.0 | 1.0 | 1.0 |
expr.Term.toString() | 4.0 | 2.0 | 3.0 | 3.0 |
Lexer.getConstant() | 2.0 | 1.0 | 3.0 | 3.0 |
Lexer.getVariable() | 2.0 | 1.0 | 3.0 | 3.0 |
Lexer.Lexer(String) | 0.0 | 1.0 | 1.0 | 1.0 |
Lexer.next() | 4.0 | 2.0 | 4.0 | 5.0 |
Lexer.peek() | 0.0 | 1.0 | 1.0 | 1.0 |
MainClass.main(String[]) | 0.0 | 1.0 | 1.0 | 1.0 |
Parser.parseExpr() | 5.0 | 1.0 | 5.0 | 5.0 |
Parser.parseFactor() | 10.0 | 2.0 | 8.0 | 8.0 |
Parser.Parser(Lexer) | 0.0 | 1.0 | 1.0 | 1.0 |
Parser.parseTerm() | 1.0 | 1.0 | 2.0 | 2.0 |
Processing.postProcess(String) | 0.0 | 1.0 | 1.0 | 1.0 |
Processing.preProcess(String) | 1.0 | 1.0 | 2.0 | 2.0 |
Total | 70.0 | 39.0 | 78.0 | 82.0 |
Average | 2.0588235294117645 | 1.1470588235294117 | 2.2941176470588234 | 2.411764705882353 |
本次作业的架构比较简单,只有expr.Factor.toString()
方法的复杂度较高,这是因为我在这个方法里做了较多的判断逻辑,如幂次为 0 时 x 不输出 系数输出。我在输出 0 输出 1 的时候都做了一些特判,是因为我担心自己在其他地方的赋值不够规范,但其实有一部分判断是冗余的
Class | OCavg | OCmax | WMC |
---|---|---|---|
expr.Expr | 1.6666666666666667 | 3.0 | 10.0 |
expr.Factor | 2.4285714285714284 | 9.0 | 17.0 |
expr.Term | 2.111111111111111 | 6.0 | 19.0 |
Lexer | 2.2 | 5.0 | 11.0 |
MainClass | 1.0 | 1.0 | 1.0 |
Parser | 3.75 | 8.0 | 15.0 |
Processing | 1.5 | 2.0 | 3.0 |
Total | 76.0 | ||
Average | 2.235294117647059 | 4.857142857142857 | 10.857142857142858 |
其中 Parser 类的复杂度较高,主要是由于解析表达式时有较多的判断逻辑,判断因子是哪个因子等
本次作业的码量不算大,主要是架构的设计比较花费时间。以及我没选 OOP,花了很多时间来熟悉和读懂 Java,wwwwww…
Bug 分析
-
本次作业中,我的程序在强测和互测中都没有出现 bug
-
我在互测环节 hack 了房内的两名同学,测试点分别是
(1)*-7
(该同学的程序会输出7
)和x+(x^3+x)^6
- 我借用了往届学长在 GitHub 开源的评测机Toby-Shi-cloud/OOAutoTest:,经过修改后使之符合本次作业要求
- 通过自动打包,自动生成数据以及借用 python sympy 包自动评测的方式,测试自己的程序和房内同学的程序
性能优化分析
在整个单元我都没有在性能优化上做太多的实现,主要是担心性能优化考虑的不到位导致强测过不了,或者是性能优化导致程序可拓展性降低,不利于后续的迭代。
在第一周作业中,我把+0
的项都删掉了,同时,由于我的架构天然的会把x*x*...*x
转化成x^n
故而省略了这一步的优化
由于时间紧促,我也并没有把+项
先输出,-项
后输出,来省略一个+号
,这部分优化我在第二次作业中补上了。
第二次作业
程序架构
在本次作业中新增了括号嵌套、自定义函数和 exp 函数,其中括号嵌套在递归下降的架构中天然适用,不需要考虑
对于自定义函数,我在
Lexer
里新增了fgh
的识别,在Parser
里新增了parseSeDeFuction
方法,解析自定义函数。我新建了Function
类,用于在读入自定义函数时替换 xyz,以及在读入表达式时替换自定义函数。对于 exp 函数,我在
Factor
中新增了exp
属性,使每个项都以a*x^n*exp(...)
的形式存在,我把 exp 的次方都乘到括号内了,使架构简单。
架构迭代
Processing
我删除了后处理,把 0 项不输出和加减号放在了 toString 里进行了处理
由于有新增函数,所以我在预处理部分做了一点更改
预处理:
- 删除空格和制表符
- 删除前导零
- 将连续的加减号(最多三个)替换为单个加减号
- 将
*+
、^+
、(+
的+
删除 - 将表达式中的
exp
替换为1*e
- 在每个左括号前添加
1*
- 将以
f1*(
,g1*(
,h1*(
,e1*(
开头的字符串替换为f(
,g(
,h(
,e(
,以消除多余的数字1
- 如果字符串以加号开始,则移除它
FuncProcess
用于在读取表达式时,将自定义表达式逐层替换(通过递归,先替换最里层的)
Function
-
新增的类,包含一个属性
HashMap<String,String>
,用来存储自定义函数,其中 key 是 f/g/h,value 是该自定义函数对应的表达式(我把 xyz 分别替换成了 uvw,防止 x 的替换出现问题) -
实现了
addFunction
getFunctions
funcToString
方法
addFunction
:每读到一个新的自定义函数,就把这个自定义函数加入到 Function(HashMap)里
getFunctions
:取出所有的 Function
funcToString
:把表达式中的自定义函数替换成带入 xyz 后的字符串
Expr
表达式类
- 新增了
deepCopy
、sortFactors
、powExp
的方法
deepCopy
:深拷贝
sortFactors
:对 Factor 排序,+项在前
powExp
:exp 幂运算,把幂次和 exp 中的每个项相乘
Factor
项
-
包含四个属性,
symbol
:这一项的正负号,index
:幂次,constant
:系数,exp
:指数函数 -
实现了
deepCopy
的方法 -
修改了
mergeFactor
和toString
,加入了对 exp 的合并和输出
复杂度分析
Method | CogC | ev(G) | iv(G) | v(G) |
---|---|---|---|---|
expr.Expr.addAllExpr(Expr) | 0.0 | 1.0 | 1.0 | 1.0 |
expr.Expr.addFactor(Factor) | 0.0 | 1.0 | 1.0 | 1.0 |
expr.Expr.addTerm(Term) | 0.0 | 1.0 | 1.0 | 1.0 |
expr.Expr.deepCopy() | 1.0 | 1.0 | 2.0 | 2.0 |
expr.Expr.equals(Expr) | 8.0 | 4.0 | 6.0 | 7.0 |
expr.Expr.Expr() | 0.0 | 1.0 | 1.0 | 1.0 |
expr.Expr.getFactors() | 0.0 | 1.0 | 1.0 | 1.0 |
expr.Expr.isSingleFactor() | 8.0 | 1.0 | 10.0 | 11.0 |
expr.Expr.powExp(Expr, Integer) | 1.0 | 1.0 | 2.0 | 2.0 |
expr.Expr.simplifyExpr(Expr) | 9.0 | 4.0 | 6.0 | 6.0 |
expr.Expr.size() | 0.0 | 1.0 | 1.0 | 1.0 |
expr.Expr.sortFactors() | 0.0 | 1.0 | 1.0 | 1.0 |
expr.Expr.toString() | 18.0 | 2.0 | 7.0 | 7.0 |
expr.Factor.deepCopy() | 1.0 | 1.0 | 2.0 | 2.0 |
expr.Factor.Factor(int, BigInteger, BigInteger, Expr) | 0.0 | 1.0 | 1.0 | 1.0 |
expr.Factor.getConstant() | 0.0 | 1.0 | 1.0 | 1.0 |
expr.Factor.getExp() | 0.0 | 1.0 | 1.0 | 1.0 |
expr.Factor.getIndexX() | 0.0 | 1.0 | 1.0 | 1.0 |
expr.Factor.getSymbol() | 0.0 | 1.0 | 1.0 | 1.0 |
expr.Factor.mergeFactor(Factor) | 3.0 | 1.0 | 2.0 | 3.0 |
expr.Factor.toString() | 26.0 | 2.0 | 17.0 | 18.0 |
expr.Term.add(Factor) | 0.0 | 1.0 | 1.0 | 1.0 |
expr.Term.addAll(Term) | 0.0 | 1.0 | 1.0 | 1.0 |
expr.Term.addFactor(Factor) | 0.0 | 1.0 | 1.0 | 1.0 |
expr.Term.getFactors() | 0.0 | 1.0 | 1.0 | 1.0 |
expr.Term.multiply(Term) | 6.0 | 1.0 | 4.0 | 4.0 |
expr.Term.pow(Expr, Integer) | 6.0 | 1.0 | 6.0 | 6.0 |
expr.Term.simplifyTerm(Term) | 9.0 | 4.0 | 6.0 | 6.0 |
expr.Term.size() | 0.0 | 1.0 | 1.0 | 1.0 |
expr.Term.Term() | 0.0 | 1.0 | 1.0 | 1.0 |
expr.Term.toString() | 4.0 | 2.0 | 3.0 | 3.0 |
Function.addFunction(String, String) | 0.0 | 1.0 | 1.0 | 1.0 |
Function.Function() | 0.0 | 1.0 | 1.0 | 1.0 |
Function.funcToString(String, String, int, String) | 3.0 | 2.0 | 2.0 | 5.0 |
Function.getFunctions() | 0.0 | 1.0 | 1.0 | 1.0 |
Lexer.getConstant() | 2.0 | 1.0 | 3.0 | 3.0 |
Lexer.getVariable() | 2.0 | 1.0 | 3.0 | 3.0 |
Lexer.Lexer(String) | 0.0 | 1.0 | 1.0 | 1.0 |
Lexer.next() | 7.0 | 2.0 | 6.0 | 8.0 |
Lexer.peek() | 0.0 | 1.0 | 1.0 | 1.0 |
MainClass.main(String[]) | 1.0 | 1.0 | 2.0 | 2.0 |
Parser.parseExpr() | 5.0 | 1.0 | 5.0 | 5.0 |
Parser.parseFactor() | 15.0 | 3.0 | 11.0 | 12.0 |
Parser.Parser(Lexer) | 0.0 | 1.0 | 1.0 | 1.0 |
Parser.parseSeDeFunction(Function) | 16.0 | 6.0 | 8.0 | 8.0 |
Parser.parseTerm() | 1.0 | 1.0 | 2.0 | 2.0 |
Processing.funcProcess(String) | 30.0 | 6.0 | 11.0 | 11.0 |
Processing.preProcess(String) | 1.0 | 1.0 | 2.0 | 2.0 |
Total | 183.0 | 74.0 | 152.0 | 162.0 |
Average | 3.8125 | 1.5416666666666667 | 3.1666666666666665 | 3.375 |
Processing.funcProcess(String)
、expr.Factor.toString()
的复杂度较高
主要是因为 funcProcess 里有 for 循环和递归的嵌套,复杂度较高,Factor.toString 中在上次作业的基础上加入了对 exp 的判断,导致复杂度更高了
Class | OCavg | OCmax | WMC |
---|---|---|---|
expr.Expr | <2.4615384615384617,2.4615384615384617> | <7.0,7.0> | <32.0,32.0> |
expr.Factor | <2.875,2.875> | <13.0,13.0> | <23.0,23.0> |
expr.Term | <2.4,2.4> | <6.0,6.0> | <24.0,24.0> |
Function | <2.25,2.25> | <6.0,6.0> | <9.0,9.0> |
Lexer | <2.6,2.6> | <7.0,7.0> | <13.0,13.0> |
MainClass | <2.0,2.0> | <2.0,2.0> | <2.0,2.0> |
Parser | <5.2,5.2> | <11.0,11.0> | <26.0,26.0> |
Processing | <5.0,5.0> | <8.0,8.0> | <10.0,10.0> |
Total | <139.0,139.0> | ||
Average | <2.8958333333333335,2.8958333333333335> | <7.5,7.5> | <17.375,17.375> |
其中 Parser 类和 Processing 类的复杂度较高,主要是由于解析表达式时有较多的判断逻辑,预处理自定义函数的时候有较多的递归替换
代码增量大概在 300 行以内,在自定义函数的递归替换部分我花了较多的时间
Bug 分析
-
本次作业中,我在强测中出现了致命的 bug 导致没有进互测房(哭)
-
我的 bug 主要都出在了字符串预处理的部分,第二周把全部的精力都放在了 exp 上,没有在字符串预处理部分做过多的思考。
一共修复了 3 个 bug
- 修复了
-(
的问题,将其转换成了-1*(
,使之对于我的设计来说是可读的 - 修复了自定义函数中无法读入空格的问题,将所有的空格删除,之前程序会因为无法继续读入而超时
- 修复了
(0+0+……+)^5
计算时多个0
相乘造成的内存爆炸问题,将其优化为(0)^5
- 修复了
性能优化分析
首先是修改了第一周残留的性能问题。把字符串后处理拿掉了,在expr.Expr.toString()
和expr.Factor.toString()
中进行处理加减号和 0 的输出问题;在化简 Expr 的同时,加入一个 sort 方法,以 symbol 来 sort,使正号的项排序在前,先输出。
本周作业其实是有较多的性能优化可以做的,但我只完成了 exp 中为单个因子时,输出一层括号的优化。此外,我也没有对 exp(0)=1 进行优化,也没有提取公因子 以 exp(…)^n 的形式输出。
第三次作业
程序架构
在本次作业中新增了在自定义函数调用自定义函数和求导的功能
对于在自定义函数调用自定义函数,我在
main
里每次读取新的自定义函数表达式时,调用一次表达式的自定义函数预处理方法Processing.funcProcess
。对于求导,我在
Factor
中新增了deriveFactor
方法,对每个项a*x^n*exp(...)
求导。我在Expr
中新增了deriveExpr
方法,对表达式求导。
架构迭代
Expr
表达式类
- 新增了
deriveExpr
方法
deriveExpr
:把 expr 中的每一项 factor 求导后得到的 term,都加到记录求导结果的 expr 中
Factor
项
- 新增了
deriveFactor
方法
deriveFactor
:对每个a*x^n*exp(...)
运用求导法则进行运算,得到每个 factor 的求导结果a*n*x^(n-1)*exp(...)+a*x^n*exp(...)*deriveExpr(...)
复杂度分析
Method | CogC | ev(G) | iv(G) | v(G) |
---|---|---|---|---|
expr.Expr.addAllExpr(Expr) | <0.0,0.0> | <1.0,1.0> | <1.0,1.0> | <1.0,1.0> |
expr.Expr.addFactor(Factor) | <0.0,0.0> | <1.0,1.0> | <1.0,1.0> | <1.0,1.0> |
expr.Expr.addTerm(Term) | <0.0,0.0> | <1.0,1.0> | <1.0,1.0> | <1.0,1.0> |
expr.Expr.deepCopy() | <1.0,1.0> | <1.0,1.0> | <2.0,2.0> | <2.0,2.0> |
expr.Expr.deriveExpr() | <1.0,1.0> | <1.0,1.0> | <2.0,2.0> | <2.0,2.0> |
expr.Expr.equals(Expr) | <8.0,8.0> | <4.0,4.0> | <6.0,6.0> | <7.0,7.0> |
expr.Expr.Expr() | <0.0,0.0> | <1.0,1.0> | <1.0,1.0> | <1.0,1.0> |
expr.Expr.getFactors() | <0.0,0.0> | <1.0,1.0> | <1.0,1.0> | <1.0,1.0> |
expr.Expr.isSingleFactor() | <8.0,8.0> | <1.0,1.0> | <10.0,10.0> | <11.0,11.0> |
expr.Expr.powExp(Expr, Integer) | <1.0,1.0> | <1.0,1.0> | <2.0,2.0> | <2.0,2.0> |
expr.Expr.simplifyExpr(Expr) | <9.0,9.0> | <4.0,4.0> | <6.0,6.0> | <6.0,6.0> |
expr.Expr.size() | <0.0,0.0> | <1.0,1.0> | <1.0,1.0> | <1.0,1.0> |
expr.Expr.sortFactors() | <0.0,0.0> | <1.0,1.0> | <1.0,1.0> | <1.0,1.0> |
expr.Expr.toString() | <18.0,18.0> | <2.0,2.0> | <7.0,7.0> | <7.0,7.0> |
expr.Factor.deepCopy() | <1.0,1.0> | <1.0,1.0> | <2.0,2.0> | <2.0,2.0> |
expr.Factor.deriveFactor() | <7.0,7.0> | <3.0,3.0> | <6.0,6.0> | <6.0,6.0> |
expr.Factor.Factor(int, BigInteger, BigInteger, Expr) | <0.0,0.0> | <1.0,1.0> | <1.0,1.0> | <1.0,1.0> |
expr.Factor.getConstant() | <0.0,0.0> | <1.0,1.0> | <1.0,1.0> | <1.0,1.0> |
expr.Factor.getExp() | <0.0,0.0> | <1.0,1.0> | <1.0,1.0> | <1.0,1.0> |
expr.Factor.getIndexX() | <0.0,0.0> | <1.0,1.0> | <1.0,1.0> | <1.0,1.0> |
expr.Factor.getSymbol() | <0.0,0.0> | <1.0,1.0> | <1.0,1.0> | <1.0,1.0> |
expr.Factor.mergeFactor(Factor) | <3.0,3.0> | <1.0,1.0> | <2.0,2.0> | <3.0,3.0> |
expr.Factor.toString() | <26.0,26.0> | <2.0,2.0> | <17.0,17.0> | <18.0,18.0> |
expr.Term.add(Factor) | <0.0,0.0> | <1.0,1.0> | <1.0,1.0> | <1.0,1.0> |
expr.Term.addAll(Term) | <0.0,0.0> | <1.0,1.0> | <1.0,1.0> | <1.0,1.0> |
expr.Term.addFactor(Factor) | <0.0,0.0> | <1.0,1.0> | <1.0,1.0> | <1.0,1.0> |
expr.Term.getFactors() | <0.0,0.0> | <1.0,1.0> | <1.0,1.0> | <1.0,1.0> |
expr.Term.multiply(Term) | <6.0,6.0> | <1.0,1.0> | <4.0,4.0> | <4.0,4.0> |
expr.Term.pow(Expr, Integer) | <6.0,6.0> | <1.0,1.0> | <6.0,6.0> | <6.0,6.0> |
expr.Term.simplifyTerm(Term) | <9.0,9.0> | <4.0,4.0> | <6.0,6.0> | <6.0,6.0> |
expr.Term.size() | <0.0,0.0> | <1.0,1.0> | <1.0,1.0> | <1.0,1.0> |
expr.Term.Term() | <0.0,0.0> | <1.0,1.0> | <1.0,1.0> | <1.0,1.0> |
expr.Term.toString() | <4.0,4.0> | <2.0,2.0> | <3.0,3.0> | <3.0,3.0> |
Function.addFunction(String, String) | <0.0,0.0> | <1.0,1.0> | <1.0,1.0> | <1.0,1.0> |
Function.Function() | <0.0,0.0> | <1.0,1.0> | <1.0,1.0> | <1.0,1.0> |
Function.funcToString(String, String, int, String) | <3.0,3.0> | <2.0,2.0> | <2.0,2.0> | <5.0,5.0> |
Function.getFunctions() | <0.0,0.0> | <1.0,1.0> | <1.0,1.0> | <1.0,1.0> |
Lexer.getConstant() | <2.0,2.0> | <1.0,1.0> | <3.0,3.0> | <3.0,3.0> |
Lexer.getVariable() | <2.0,2.0> | <1.0,1.0> | <3.0,3.0> | <3.0,3.0> |
Lexer.Lexer(String) | <0.0,0.0> | <1.0,1.0> | <1.0,1.0> | <1.0,1.0> |
Lexer.next() | <7.0,7.0> | <2.0,2.0> | <6.0,6.0> | <8.0,8.0> |
Lexer.peek() | <0.0,0.0> | <1.0,1.0> | <1.0,1.0> | <1.0,1.0> |
MainClass.main(String[]) | <1.0,1.0> | <1.0,1.0> | <2.0,2.0> | <2.0,2.0> |
Parser.parseDerive() | <0.0,0.0> | <1.0,1.0> | <1.0,1.0> | <1.0,1.0> |
Parser.parseExp() | <1.0,1.0> | <1.0,1.0> | <2.0,2.0> | <2.0,2.0> |
Parser.parseExpr() | <5.0,5.0> | <1.0,1.0> | <5.0,5.0> | <5.0,5.0> |
Parser.parseFactor() | <14.0,14.0> | <4.0,4.0> | <11.0,11.0> | <12.0,12.0> |
Parser.Parser(Lexer) | <0.0,0.0> | <1.0,1.0> | <1.0,1.0> | <1.0,1.0> |
Parser.parseSeDeFunction(Function) | <16.0,16.0> | <6.0,6.0> | <8.0,8.0> | <8.0,8.0> |
Parser.parseTerm() | <1.0,1.0> | <1.0,1.0> | <2.0,2.0> | <2.0,2.0> |
Processing.funcProcess(String) | <31.0,31.0> | <6.0,6.0> | <12.0,12.0> | <12.0,12.0> |
Processing.preProcess(String) | <1.0,1.0> | <1.0,1.0> | <2.0,2.0> | <2.0,2.0> |
Total | <192.0,192.0> | <81.0,81.0> | <164.0,164.0> | <174.0,174.0> |
Average | <3.6923076923076925,3.6923076923076925> | <1.5576923076923077,1.5576923076923077> | <3.1538461538461537,3.1538461538461537> | <3.3461538461538463,3.3461538461538463> |
新增方法的复杂度都不高
代码增量只有不到 100 行,本次作业对我来说相对轻松,之前的架构能很好地完成本次作业迭代
Bug 分析
-
本次作业中,我在自测时发现了一个 bug
2
f(y,x)=y^2
g(y,x)=f(x,y)
g(1,5)应该输出 25,但我的程序输出了 1。这是因为在自定义函数字符串替换的时候,会把替换后的 uvw 看作是还没有被替换的东西,进行了重复的替换。
解决方法:把每个形参用不同的值进行存储,不要统一使用 uvw。我的解决方法是用 fu fv fw gu gv…来代替 uvw,从而保证不会有重复替换的情况出现。
-
在强测中,我成功 hack 了房间里的一名同学
2
f(y,x,z)=1
g(z)=f(1,1,1)
f(1,1,g(1))该同学的程序会抛出异常
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 3
at FuncMap.submit0(FuncMap.java:96)
at FuncMap.submit(FuncMap.java:41)
at Main.main(Main.java:29)
第一单元作业总结
由于是第一次接触 Java,我的架构设计的并不是很理想,在最开始的一两周不是很理解什么是接口,继承这些关系,也一直不懂为什么同学们的架构中都加入了Poly
和Mono
这两个类。直到这周的研讨课,听了同学对自己架构的分享我才理解。我确实认为加入了Poly
和Mono
的结构是更合适的,从架构上也更符合自下而上的思想,读写分离使得操作更加方便清晰。
而我的架构的弊端也显而易见
-
用看似是 expr term factor 的命名,实际他们可能是以 poly tempPoly Mono 的形式存在的,感觉程序的架构不是很容易表述清楚,很容易让别人误解。
-
在 Factor 中没有使用接口,我认为程序的可拓展性是大幅下降的。同时,为了能让数据在 Expr Term Factor 中传输,我多写了很多方法,但如果使用接口就不需要这么麻烦了。
-
相比加入了
Poly
和Mono
的架构而言,我的架构不够清晰,可扩展性也比较低。
如果能再来一次,能不能让我在上个学期就知道有 oop 这门课啊(哭)