OO第一单元总结
- 复杂度分析各参数的意义
- CogC(Cognitive Complexity):衡量一个代码单元直观理解的难易程度。
- ev(G)(Essential Cyclomatic Complexity):模块包含非结构化结构的程度的度量。
- iv(G)(Design Complexity):是模块决策结构的量度,因为它与对其他模块的调用相关.
- v(G)(Cyclomatic Complexity):是通过源代码的线性独立路径的计数。
- OCavg(Average operation Complexity):平均方法复杂度
- OCmax(maximun operation Complexity):方法复杂度的最大值
- WMC(weighted method Complexity):加权方法复杂度,衡量一个类的复杂性
第一次作业
作业要求简述
- 本次作业要求支持含有至多一层括号、加减乘、乘方的表达式的计算的化简。
作业思路
- 本次作业其实在一开始写的时候本意是想使用正则表达式建立一个表达式树,然后通过遍历方式去计算,并且忘记了看第一次训练。。。。。当时越往下做越感觉会出错,于是便在思考重构。。后来在做第一次实验的时候,那个递归下降的框架给了我一个好思路,于是我便是采用与第一次实验时差不多的架构。
- 对表达式进行解析,先去遍历一些运算级较低的符号
+/-
,之后去遍历*
等符号,进行层次解析,最终解析到x
、常数、或者空串。这些+,-,*
等都有一个自己的class
,并且有left,right
等属性,之后通过逐层调用getResults
函数,每次调用都得到一个运算后的Hashmap
,经过一些运算后又会得到一个新的Hashmap
,这样逐层进行运算,最终得到一个表达式的Hashmap
,然后输出。
- 本次作业采用了
递归下降
的做法,有利于之后的迭代开发
UML
图:
复杂度分析
Method |
CogC |
ev(G) |
iv(G) |
v(G) |
Add.Add(Operate, Operate) |
0 |
1 |
1 |
1 |
Add.getResults() |
4 |
1 |
3 |
3 |
Exp.Exp(Operate, Operate) |
0 |
1 |
1 |
1 |
Exp.getResults() |
4 |
1 |
3 |
3 |
Exp.mul(HashMap<Integer, BigDecimal>, HashMap<Integer, BigDecimal>) |
7 |
1 |
4 |
4 |
MainClass.findzeros(HashMap<Integer, BigDecimal>) |
3 |
1 |
2 |
3 |
MainClass.main(String[]) |
17 |
4 |
6 |
7 |
Mul.Mul(Operate, Operate) |
0 |
1 |
1 |
1 |
Mul.getResults() |
7 |
1 |
4 |
4 |
Number.Number(HashMap<Integer, BigDecimal>) |
0 |
1 |
1 |
1 |
Number.getResults() |
0 |
1 |
1 |
1 |
Operate.Operate(Operate, Operate) |
0 |
1 |
1 |
1 |
Operate.getLeft() |
0 |
1 |
1 |
1 |
Operate.getResults() |
0 |
1 |
1 |
1 |
Operate.getRight() |
0 |
1 |
1 |
1 |
Parser.Parser(String) |
0 |
1 |
1 |
1 |
Parser.del(String) |
0 |
1 |
1 |
1 |
Parser.findAddorSub(String) |
14 |
4 |
7 |
10 |
Parser.findBracLeft(String) |
3 |
1 |
2 |
3 |
Parser.findBracRight(String) |
3 |
1 |
2 |
3 |
Parser.findMul(String) |
8 |
4 |
7 |
10 |
Parser.findPow(String) |
9 |
4 |
4 |
7 |
Parser.getResult() |
0 |
1 |
1 |
1 |
Parser.parse(String) |
23 |
7 |
9 |
9 |
Sub.Sub(Operate, Operate) |
0 |
1 |
1 |
1 |
Sub.getResults() |
4 |
1 |
3 |
3 |
Total |
106 |
44 |
69 |
82 |
Average |
4.08 |
1.69 |
2.65 |
3.15 |
Class |
OCavg |
OCmax |
WMC |
Number |
1.0 |
1.0 |
2.0 |
Operate |
1.0 |
1.0 |
4.0 |
Add |
2.0 |
3.0 |
4.0 |
Sub |
2.0 |
3.0 |
4.0 |
Exp |
2.67 |
4.0 |
8.0 |
Mul |
2.5 |
4.0 |
5.0 |
MainClass |
5.0 |
7.0 |
10.0 |
Parser |
3.67 |
8.0 |
33.0 |
Total |
|
|
70.0 |
Average |
2.69 |
3.875 |
8.75 |
本次作业的不足
- 本次作业未能达到最好的优化,比如
1*x
这种我都没有优化,当时属于是想偷懒了,于是第二次作业优化便翻车了。。。。
bug分析及Hack策略
- 这次作业中,由于架构比较不算复杂,于是没有什么
bug
,但之后就有了。。。
- 我
hack
了别人两次,通过看代码查出来一处错误
第二次作业
作业要求简述
- 这次作业比第一次作业高了一个级别,需要支持
sin
、cos
、自定义函数、求和函数,自定义函数不可自己调用,其中三角函数中的只能是包含x
的幂函数以及常数,其实一开始的要求不是这样的,可见助教们还是手下留情了。
作业思路
- 这次作业我在写的时候考虑的一个最大的问题便是如何去存储每个运算符运算后的结果,我总共思考了两种方法
- 将
Hashmap
的键抽象为类,优点是每个运算符的getResults()
函数只需做一些小改动即可,缺点是不适合之后三角函数的优化,比如sin^2+cos^2=1
这种优化
- 将
Hashmap
的键值抽象为类,优点是方便三角函数的优化,缺点是每个运算符的getResults()
函数需要做比较大的改变
- 在博弈了两者优缺点之后,我选择了第一种并实现了
Item
这个类,当然,这也直接导致了后期想要进一步优化(指sin
和cos
的优化)的时候特别麻烦
import java.util.ArrayList;
public class Item {
private ArrayList<String> contentSin = new ArrayList<>();
private ArrayList<String> contentCos = new ArrayList<>();
private final Integer pow;
public Item(Integer pow, ArrayList<String> contentCos, ArrayList<String> contentSin) {
this.pow = pow;
this.contentCos = contentCos;
this.contentSin = contentSin;
}
public ArrayList<String> getContentCos() {
return contentCos;
}
public ArrayList<String> getContentSin() {
return contentSin;
}
public Integer getPow() {
return pow;
}
}
UML
图
复杂度分析
Method |
CogC |
ev(G) |
iv(G) |
v(G) |
Add.Add(Operate, Operate) |
0 |
1 |
1 |
1 |
Add.getResults() |
4 |
1 |
3 |
3 |
Exp.Exp(Operate, Operate) |
0 |
1 |
1 |
1 |
Exp.getResults() |
5 |
1 |
4 |
4 |
Item.Item(Integer, ArrayList, ArrayList) |
0 |
1 |
1 |
1 |
Item.getContentCos() |
0 |
1 |
1 |
1 |
Item.getContentSin() |
0 |
1 |
1 |
1 |
Item.getPow() |
0 |
1 |
1 |
1 |
MainClass.add(HashMap<Item, BigDecimal>, Item, BigDecimal) |
4 |
3 |
5 |
5 |
MainClass.equalLists(ArrayList, ArrayList) |
4 |
3 |
3 |
6 |
MainClass.findzeros(HashMap<Item, BigDecimal>) |
3 |
1 |
2 |
3 |
MainClass.main(String[]) |
8 |
4 |
4 |
5 |
MainClass.merge(HashMap<Item, BigDecimal>) |
3 |
1 |
3 |
3 |
MainClass.outCoe(Item, BigDecimal, int, StringBuilder) |
15 |
1 |
14 |
14 |
MainClass.outTrig(Item, StringBuilder) |
15 |
1 |
12 |
12 |
MainClass.outVar(Item, StringBuilder, BigDecimal) |
1 |
1 |
1 |
4 |
MainClass.sum(ArrayList) |
10 |
1 |
4 |
5 |
Mul.Mul(Operate, Operate) |
0 |
1 |
1 |
1 |
Mul.getContent(ArrayList, ArrayList) |
0 |
1 |
1 |
1 |
Mul.getResults() |
7 |
1 |
4 |
4 |
Number.Number(HashMap<Item, BigDecimal>) |
0 |
1 |
1 |
1 |
Number.getResults() |
0 |
1 |
1 |
1 |
Operate.Operate(Operate, Operate) |
0 |
1 |
1 |
1 |
Operate.getLeft() |
0 |
1 |
1 |
1 |
Operate.getResults() |
0 |
1 |
1 |
1 |
Operate.getRight() |
0 |
1 |
1 |
1 |
Parser.Parser(String, ArrayList) |
0 |
1 |
1 |
1 |
Parser.dealCustomFunc(String, ArrayList) |
12 |
3 |
9 |
10 |
Parser.dealSum(String, ArrayList) |
1 |
1 |
2 |
2 |
Parser.dealTrigFunc(String, ArrayList) |
16 |
3 |
17 |
17 |
Parser.del(String) |
0 |
1 |
1 |
1 |
Parser.findAddOrSub(String) |
13 |
4 |
6 |
9 |
Parser.findBracLeft(String) |
2 |
1 |
2 |
3 |
Parser.findBracRight(String) |
2 |
1 |
3 |
3 |
Parser.findCustomFunc(String) |
26 |
4 |
12 |
14 |
Parser.findMul(String) |
8 |
4 |
7 |
10 |
Parser.findPow(String) |
9 |
4 |
4 |
7 |
Parser.findSum(String) |
27 |
4 |
13 |
15 |
Parser.findTrigFunc(String) |
28 |
4 |
15 |
17 |
Parser.getResult() |
0 |
1 |
1 |
1 |
Parser.parse(String) |
26 |
10 |
13 |
13 |
Parser.setFunc(ArrayList) |
3 |
1 |
2 |
3 |
Sub.Sub(Operate, Operate) |
0 |
1 |
1 |
1 |
Sub.getResults() |
4 |
1 |
3 |
3 |
TrigFunc.TrigFunc(String, String) |
2 |
1 |
3 |
3 |
TrigFunc.getResults() |
0 |
1 |
1 |
1 |
Class |
OCavg |
OCmax |
WMC |
Item |
1.0 |
1.0 |
4.0 |
Number |
1.0 |
1.0 |
2.0 |
Operate |
1.0 |
1.0 |
4.0 |
Add |
2.0 |
3.0 |
4.0 |
Sub |
2.0 |
3.0 |
4.0 |
TrigFunc |
2.0 |
3.0 |
4.0 |
Exp |
2.5 |
4.0 |
5.0 |
Mul |
2.0 |
4.0 |
6.0 |
MainClass |
4.78 |
9.0 |
43.0 |
Parser |
5.68 |
11.0 |
91.0 |
Total |
|
|
167.0 |
Average |
3.63 |
4.0 |
16.7 |
本次作业的不足
- 本次作业优化未能达到最优,尤其是关于三角函数的优化,并且优化还翻车了是(ノへ ̄、)
bug分析及Hack策略
- 本次作业强测中发现了一个
bug
,互测中被Hack
了两次,究其原因,还是自己最后有些贪性能分了又没有好好去想怎么优化,将最终得到的字符串中的1*
全都replace
为空了,这直接导致了11*x
输出1x
,于是便出错了
- 其实这次作业还有一个隐藏
bug
,那就是sum
求和函数的i
我当时使用的是int
去存储,这个错误一直到第三次作业互测才被发现。。。
- 本次互测未发现别人
bug
第三次作业
作业要求简述
- 本次作业主要是添加了括号嵌套、三角函数内容可包含表达式、自定义函数嵌套,当然自定义函数在定义时同样不可自己调用,相比于上次作业而言,形式更为复杂。
作业思路
- 由于我采用的是递归下降的方法,所以不用改动太多,因此这次我的主要改动是体现在优化输出上了。
- 层次化的输出:先输出符号,再输出系数,然后是变量,最后是指数。之后分别优化便可。
- 其实三角函数的输出跟最终结果的输出有很大的相似之处的,所以说主要还是在于性能上了,比如有些可以不加括号的,而有些是必须要加括号的,我是特殊情况特殊判断的,代码如下
boolean cosEmpty = st.getContentCos().isEmpty();
boolean sinEmpty = st.getContentSin().isEmpty();
boolean powIsZero = st.getPow() == 0;
boolean coeIsOne = result.get(st).equals(new BigDecimal(1));
boolean numberOnly = (size == 1 && (cosEmpty && sinEmpty && powIsZero));
boolean varOnly = (size == 1 && cosEmpty && sinEmpty && coeIsOne);
boolean cosOnly = (size == 1 && sinEmpty
&& powIsZero && coeIsOne && st.getContentCos().size() == 1);
boolean sinOnly = (size == 1 && cosEmpty
&& powIsZero && coeIsOne && st.getContentSin().size() == 1);
if (numberOnly) { outCoe(st, result.get(st), output); }
else if (varOnly) {
output.append("x");
if (st.getPow() > 1) {
output.append("**").append(st.getPow());
}
}
else if (sinOnly) {
output.append("sin(").append(st.getContentSin().get(0)).append(")");
}
else if (cosOnly) {
output.append("cos(").append(st.getContentCos().get(0)).append(")");
}
UML
图
复杂度分析
Method |
CogC |
ev(G) |
iv(G) |
v(G |
Add.Add(Operate, Operate) |
0.0 |
1.0 |
1.0 |
1.0 |
Add.find(HashMap, Item, BigDecimal) |
3.0 |
3.0 |
3.0 |
3.0 |
Add.getResults() |
3.0 |
1.0 |
3.0 |
3.0 |
CustomFunc.CustomFunc(String, String, HashMap) |
0.0 |
1.0 |
1.0 |
1.0 |
CustomFunc.execute(String, String, HashMap) |
15.0 |
3.0 |
12.0 |
13.0 |
CustomFunc.findComma(String) |
8.0 |
4.0 |
4.0 |
6.0 |
CustomFunc.getExpr() |
0.0 |
1.0 |
1.0 |
1.0 |
CustomFunc.getResults() |
0.0 |
1.0 |
1.0 |
1.0 |
CustomFunc.setResults(HashMap) |
0.0 |
1.0 |
1.0 |
1.0 |
Exp.Exp(Operate, Operate) |
0.0 |
1.0 |
1.0 |
1.0 |
Exp.getResults() |
5.0 |
1.0 |
4.0 |
4.0 |
Item.equalLists(ArrayList, ArrayList) |
4.0 |
3.0 |
3.0 |
6.0 |
Item.equals(Item) |
1.0 |
1.0 |
3.0 |
3.0 |
Item.getContentCos() |
0.0 |
1.0 |
1.0 |
1.0 |
Item.getContentSin() |
0.0 |
1.0 |
1.0 |
1.0 |
Item.getPow() |
0.0 |
1.0 |
1.0 |
1.0 |
Item.Item(Integer, ArrayList, ArrayList) |
0.0 |
1.0 |
1.0 |
1.0 |
MainClass.main(String[]) |
1.0 |
1.0 |
2.0 |
2.0 |
Mul.find(HashMap, Item, BigDecimal) |
3.0 |
3.0 |
3.0 |
3.0 |
Mul.getContent(ArrayList, ArrayList) |
0.0 |
1.0 |
1.0 |
1.0 |
Mul.getResults() |
6.0 |
1.0 |
4.0 |
4.0 |
Mul.Mul(Operate, Operate) |
0.0 |
1.0 |
1.0 |
1.0 |
Number.getResults() |
0.0 |
1.0 |
1.0 |
1.0 |
Number.Number(HashMap) |
0.0 |
1.0 |
1.0 |
1.0 |
Operate.getLeft() |
0.0 |
1.0 |
1.0 |
1.0 |
Operate.getResults() |
0.0 |
1.0 |
1.0 |
1.0 |
Operate.getRight() |
0.0 |
1.0 |
1.0 |
1.0 |
Operate.Operate(Operate, Operate) |
0.0 |
1.0 |
1.0 |
1.0 |
Parser.buildString(HashMap) |
7.0 |
4.0 |
3.0 |
4.0 |
Parser.dealCustomFunc(String, ArrayList) |
0.0 |
1.0 |
1.0 |
1.0 |
Parser.dealSum(String, ArrayList) |
1.0 |
1.0 |
2.0 |
2.0 |
Parser.dealTrigFunc(String, ArrayList) |
1.0 |
1.0 |
3.0 |
3.0 |
Parser.del(String) |
0.0 |
1.0 |
1.0 |
1.0 |
Parser.findAddOrSub(String) |
13.0 |
4.0 |
6.0 |
9.0 |
Parser.findBracLeft(String) |
2.0 |
1.0 |
2.0 |
3.0 |
Parser.findBracRight(String) |
2.0 |
1.0 |
3.0 |
3.0 |
Parser.findCustomFunc(String) |
4.0 |
1.0 |
6.0 |
6.0 |
Parser.findMul(String) |
8.0 |
4.0 |
7.0 |
10.0 |
Parser.findPow(String) |
9.0 |
4.0 |
4.0 |
7.0 |
Parser.findSum(String) |
4.0 |
1.0 |
6.0 |
6.0 |
Parser.findTrigFunc(String) |
6.0 |
1.0 |
9.0 |
9.0 |
Parser.findzeros(HashMap) |
3.0 |
1.0 |
2.0 |
3.0 |
Parser.outCoe(Item, BigDecimal, int, StringBuilder) |
2.0 |
1.0 |
3.0 |
3.0 |
Parser.outTrig(Item, StringBuilder) |
0.0 |
1.0 |
1.0 |
1.0 |
Parser.outVar(Item, StringBuilder) |
0.0 |
1.0 |
1.0 |
1.0 |
Parser.parse(String) |
26.0 |
10.0 |
13.0 |
13.0 |
Parser.Parser(String, ArrayList) |
0.0 |
1.0 |
1.0 |
1.0 |
Parser.setFunc(ArrayList) |
3.0 |
1.0 |
2.0 |
3.0 |
Parser.sort(HashMap) |
1.0 |
1.0 |
2.0 |
2.0 |
Parser.sum(ArrayList) |
0.0 |
1.0 |
1.0 |
1.0 |
Parser.toString() |
0.0 |
1.0 |
1.0 |
1.0 |
Sub.find(HashMap, Item, BigDecimal) |
3.0 |
3.0 |
3.0 |
3.0 |
Sub.getResults() |
3.0 |
1.0 |
3.0 |
3.0 |
Sub.Sub(Operate, Operate) |
0.0 |
1.0 |
1.0 |
1.0 |
TrigFunc.buildCoe(Item, BigDecimal, StringBuilder, Integer) |
2.0 |
1.0 |
3.0 |
3.0 |
TrigFunc.findzeros(HashMap) |
3.0 |
1.0 |
2.0 |
3.0 |
TrigFunc.generateTrig(Item, StringBuilder, HashMap, HashMap) |
15.0 |
1.0 |
12.0 |
12.0 |
TrigFunc.genVar(Item, StringBuilder) |
1.0 |
1.0 |
1.0 |
4.0 |
TrigFunc.getResults() |
9.0 |
3.0 |
11.0 |
13.0 |
TrigFunc.getStringIntegerHashMap(ArrayList) |
10.0 |
1.0 |
4.0 |
5.0 |
TrigFunc.out() |
27.0 |
9.0 |
17.0 |
26.0 |
TrigFunc.outCoe(Item, BigDecimal, StringBuilder) |
13.0 |
1.0 |
12.0 |
12.0 |
TrigFunc.outTrig(Item, StringBuilder) |
0.0 |
1.0 |
1.0 |
1.0 |
TrigFunc.outVar(Item, StringBuilder) |
0.0 |
1.0 |
1.0 |
1.0 |
TrigFunc.sort(HashMap) |
1.0 |
1.0 |
2.0 |
2.0 |
TrigFunc.TrigFunc(HashMap, boolean) |
0.0 |
1.0 |
1.0 |
1.0 |
Total |
228.0 |
110.0 |
213.0 |
248.0 |
Average |
3.454 |
1.667 |
3.2273 |
3.758 |
Class |
OCavg |
OCmax |
WMC |
Number |
1.0 |
1.0 |
2.0 |
Operate |
1.0 |
1.0 |
4.0 |
MainClass |
2.0 |
2.0 |
2.0 |
Add |
2.33 |
3.0 |
7.0 |
Item |
1.33 |
3.0 |
8.0 |
Sub |
2.33 |
3.0 |
7.0 |
Exp |
2.5 |
4.0 |
5.0 |
Mul |
2.25 |
4.0 |
9.0 |
Parser |
2.78 |
11.0 |
64.0 |
TrigFunc |
4.25 |
11.0 |
51.0 |
CustomFunc |
3.67 |
13.0 |
22.0 |
Total |
|
|
181.0 |
Average |
2.74 |
5.09 |
16.46 |
本次作业的不足
- 这次作业未能优化
sin(x)**2+cos(x)**2 = 1
的问题,以及sin(x)+sin((-x)) = 0
的问题导致性能分有点低,主要应该还是架构的问题吧。
bug分析及Hack策略
sum
未考虑i
为大数的时候的情况,导致被Hack
了四次
- 总共
Hack
了他人两次,其中一次是盲砍中的是o( ̄▽ ̄)d,后边想知道是怎么中的,又砍了一次(✿◠‿◠)
总结
pre
做完之后对与Java
有了一个认识,但当时还没有好的架构这个概念。因此第一单元的架构感觉设计得不算很好,导致性能分有些拉跨。尤其是在写第一次作业的时候,花了比较长的时间,其原因还是心里没有架构这个概念,另外就是对Java
的一些数据结构不算特别了解。还有就是没能实现一个评测机的编写。希望在之后的几次单元里好好设计自己的架构,不要着急写代码,并完成一个评测机。