309
社区成员
发帖
与我相关
我的任务
分享
| 类/接口 | 方法数量 | 代码长度 | 说明 |
|---|---|---|---|
Factor | 0 | 0 | 因子接口,表达式的任何组成部分都可视为因子 |
Expr | 6 | 35行 | 项组 |
Term | 7 | 46行 | 因子组 |
Power | 4 | 26行 | 一个因子及其指数 |
Deriver | 5 | 30行 | 求导因子 |
Number | 6 | 37行 | 常数因子 |
Var | 4 | 37行 | 变量因子 |
Exp | 15 | 173行 | 指数函数因子 |
Selector | 4 | 57行 | 选择式,未使用Factor接口,在处理阶段就完成计算与替换 |
Func | 7 | 67行 | 函数,未使用Factor接口,在处理阶段就完成替换 |
RecurseFunc | 5 | 64行 | Func子类,处理同上 |
| 类/接口 | 方法数量 | 类长度 | 说明 |
|---|---|---|---|
Poly | 13 | 250行 | 多项式类,使用HashMap实现,同时包含+,-,*,^以及求导等多种运算 |
Key | 5 | 56行 | 自定义的Poly类的HashMap的键,包含exponentX,exponentY和Exp三个属性 |
Visitor | 7 | 27行 | 访问者模式接口 |
Displayer | 7 | 151行 | 具体访问者类 |
| 类/接口 | 方法数量 | 类长度 | 说明 |
|---|---|---|---|
Lexer | 8 | 109行 | 解析 |
Parser | 5 | 89行 | 递归下降 |
Dealer | 17 | 385行 | 处理类,包括了输入处理和输出打印,选择式和函数的替换都在这里完成 |
| Method | CogC | ev(G) | iv(G) | v(G) |
|---|---|---|---|---|
| Main.main(String[]) | 0 | 1 | 1 | 1 |
| expression.Deriver.Deriver(Expr, String) | 0 | 1 | 1 | 1 |
| expression.Deriver.accept(Visitor) | 0 | 1 | 1 | 1 |
| expression.Deriver.getExpr() | 0 | 1 | 1 | 1 |
| expression.Deriver.getType() | 0 | 1 | 1 | 1 |
| expression.Deriver.toPoly(Visitor) | 0 | 1 | 1 | 1 |
| expression.Exp.Exp(String) | 0 | 1 | 1 | 1 |
| expression.Exp.accept(Visitor) | 0 | 1 | 1 | 1 |
| expression.Exp.deX() | 0 | 1 | 1 | 1 |
| expression.Exp.deY() | 0 | 1 | 1 | 1 |
| expression.Exp.equals(Object) | 5 | 4 | 3 | 5 |
| expression.Exp.getExp() | 0 | 1 | 1 | 1 |
| expression.Exp.getHashMap(HashMap<Key, BigInteger>) | 4 | 1 | 3 | 3 |
| expression.Exp.getPoly() | 0 | 1 | 1 | 1 |
| expression.Exp.getPolySize() | 0 | 1 | 1 | 1 |
| expression.Exp.mul(Exp) | 0 | 1 | 1 | 1 |
| expression.Exp.optimize() | 9 | 1 | 7 | 7 |
| expression.Exp.parse() | 2 | 1 | 2 | 2 |
| expression.Exp.pow(int) | 0 | 1 | 1 | 1 |
| expression.Exp.toPoly() | 0 | 1 | 1 | 1 |
| expression.Exp.toString() | 8 | 3 | 5 | 6 |
| expression.Expr.Expr() | 0 | 1 | 1 | 1 |
| expression.Expr.accept(Visitor) | 0 | 1 | 1 | 1 |
| expression.Expr.addOp(String) | 0 | 1 | 1 | 1 |
| expression.Expr.addTerm(Term) | 0 | 1 | 1 | 1 |
| expression.Expr.getOps() | 0 | 1 | 1 | 1 |
| expression.Expr.getTerms() | 0 | 1 | 1 | 1 |
| expression.Func.Func(String) | 0 | 1 | 1 | 1 |
| expression.Func.body() | 0 | 1 | 1 | 1 |
| expression.Func.getBody(String) | 5 | 1 | 4 | 4 |
| expression.Func.getFunc() | 0 | 1 | 1 | 1 |
| expression.Func.getParam() | 0 | 1 | 1 | 1 |
| expression.Func.parse() | 4 | 4 | 4 | 4 |
| expression.Func.setParam(String) | 0 | 1 | 1 | 1 |
| expression.Key.Key(BigInteger, BigInteger, Exp) | 0 | 1 | 1 | 1 |
| expression.Key.equals(Object) | 12 | 6 | 6 | 10 |
| expression.Key.getExp() | 0 | 1 | 1 | 1 |
| expression.Key.getExponentX() | 0 | 1 | 1 | 1 |
| expression.Key.getExponentY() | 0 | 1 | 1 | 1 |
| expression.Number.Number(BigInteger) | 0 | 1 | 1 | 1 |
| expression.Number.accept(Visitor) | 0 | 1 | 1 | 1 |
| expression.Number.getNum() | 0 | 1 | 1 | 1 |
| expression.Number.getNumber() | 0 | 1 | 1 | 1 |
| expression.Number.toPoly() | 0 | 1 | 1 | 1 |
| expression.Number.toString() | 0 | 1 | 1 | 1 |
| expression.Poly.Poly(HashMap<Key, BigInteger>) | 0 | 1 | 1 | 1 |
| expression.Poly.add(Poly) | 9 | 2 | 4 | 5 |
| expression.Poly.copyPoly() | 0 | 1 | 1 | 1 |
| expression.Poly.deX() | 7 | 1 | 4 | 4 |
| expression.Poly.deY() | 7 | 1 | 4 | 4 |
| expression.Poly.derivative(String) | 1 | 4 | 4 | 4 |
| expression.Poly.getExists(HashMap<Key, BigInteger>, Key) | 3 | 3 | 2 | 3 |
| expression.Poly.getMap() | 0 | 1 | 1 | 1 |
| expression.Poly.mul(Poly) | 8 | 2 | 5 | 5 |
| expression.Poly.power(BigInteger) | 8 | 3 | 4 | 4 |
| expression.Poly.sub(Poly) | 9 | 2 | 4 | 5 |
| expression.Poly.toMap() | 0 | 1 | 1 | 1 |
| expression.Poly.toString() | 0 | 1 | 1 | 1 |
| expression.Power.Power(Factor, Factor) | 0 | 1 | 1 | 1 |
| expression.Power.accept(Visitor) | 0 | 1 | 1 | 1 |
| expression.Power.getBase() | 0 | 1 | 1 | 1 |
| expression.Power.getExponent() | 0 | 1 | 1 | 1 |
| expression.RecurseFunc.RecurseFunc(String, Func, Func) | 0 | 1 | 1 | 1 |
| expression.RecurseFunc.expand(int) | 3 | 3 | 3 | 3 |
| expression.RecurseFunc.getBody(String) | 5 | 1 | 4 | 4 |
| expression.RecurseFunc.setCurse(int) | 0 | 1 | 1 | 1 |
| expression.RecurseFunc.setFunc(Func) | 0 | 1 | 1 | 1 |
| expression.Selector.Selector(String, Func, RecurseFunc) | 0 | 1 | 1 | 1 |
| expression.Selector.getRes() | 2 | 2 | 1 | 2 |
| expression.Selector.parseSelect() | 0 | 1 | 1 | 1 |
| expression.Selector.select() | 0 | 1 | 1 | 1 |
| expression.Term.Term() | 0 | 1 | 1 | 1 |
| expression.Term.accept(Visitor) | 0 | 1 | 1 | 1 |
| expression.Term.addFactors(Factor) | 0 | 1 | 1 | 1 |
| expression.Term.addOps(String) | 0 | 1 | 1 | 1 |
| expression.Term.getFactors() | 0 | 1 | 1 | 1 |
| expression.Term.getOps() | 0 | 1 | 1 | 1 |
| expression.Term.toString() | 1 | 1 | 2 | 2 |
| expression.Var.Var(String) | 0 | 1 | 1 | 1 |
| expression.Var.accept(Visitor) | 0 | 1 | 1 | 1 |
| expression.Var.toPoly() | 2 | 1 | 2 | 3 |
| expression.Var.toString() | 0 | 1 | 1 | 1 |
| parse.Lexer.Lexer(String) | 0 | 1 | 1 | 1 |
| parse.Lexer.getDerive() | 2 | 1 | 3 | 3 |
| parse.Lexer.getExp() | 7 | 5 | 5 | 5 |
| parse.Lexer.getNum(String) | 2 | 1 | 3 | 3 |
| parse.Lexer.next() | 7 | 2 | 5 | 7 |
| parse.Lexer.peek() | 0 | 1 | 1 | 1 |
| parse.Lexer.removeFront0(String) | 4 | 2 | 2 | 3 |
| parse.Lexer.toString() | 0 | 1 | 1 | 1 |
| parse.Parser.Parser(Lexer) | 0 | 1 | 1 | 1 |
| parse.Parser.parseExpr() | 2 | 1 | 3 | 3 |
| parse.Parser.parseFactor() | 7 | 5 | 7 | 7 |
| parse.Parser.parsePower() | 2 | 2 | 2 | 2 |
| parse.Parser.parseTerm() | 1 | 1 | 2 | 2 |
| visitor.Dealer.Dealer() | 0 | 1 | 1 | 1 |
| visitor.Dealer.addBracket() | 5 | 1 | 3 | 4 |
| visitor.Dealer.addZero() | 11 | 2 | 6 | 10 |
| visitor.Dealer.changeSub() | 6 | 1 | 5 | 5 |
| visitor.Dealer.deal() | 2 | 1 | 3 | 3 |
| visitor.Dealer.eleString(Key, BigInteger) | 5 | 1 | 4 | 6 |
| visitor.Dealer.getArg() | 6 | 2 | 4 | 5 |
| visitor.Dealer.getSelect(int) | 3 | 3 | 2 | 3 |
| visitor.Dealer.getValueStr(BigInteger, BigInteger, String) | 34 | 1 | 10 | 10 |
| visitor.Dealer.getVarStr(BigInteger, String, String) | 3 | 3 | 2 | 3 |
| visitor.Dealer.print(Poly) | 9 | 7 | 5 | 8 |
| visitor.Dealer.readInput() | 5 | 1 | 3 | 4 |
| visitor.Dealer.removeAdd() | 8 | 1 | 3 | 5 |
| visitor.Dealer.removeNull(Poly) | 4 | 2 | 3 | 4 |
| visitor.Dealer.replaceFunc() | 21 | 2 | 9 | 10 |
| visitor.Dealer.replaceSelect() | 0 | 1 | 1 | 1 |
| visitor.Dealer.setDealer(String, Func, RecurseFunc) | 0 | 1 | 1 | 1 |
| visitor.Displayer.visit(Deriver) | 0 | 1 | 1 | 1 |
| visitor.Displayer.visit(Exp) | 0 | 1 | 1 | 1 |
| visitor.Displayer.visit(Expr) | 10 | 3 | 5 | 6 |
| visitor.Displayer.visit(Number) | 0 | 1 | 1 | 1 |
| visitor.Displayer.visit(Power) | 9 | 8 | 9 | 9 |
| visitor.Displayer.visit(Term) | 12 | 8 | 9 | 9 |
| visitor.Displayer.visit(Var) | 0 | 1 | 1 | 1 |
| Class | OCavg | OCmax | WMC | |
| Main | 1 | 1 | 1 | |
| expression.Deriver | 1 | 1 | 5 | |
| expression.Exp | 1.87 | 5 | 28 | |
| expression.Expr | 1 | 1 | 6 | |
| expression.Func | 1.86 | 4 | 13 | |
| expression.Key | 2 | 6 | 10 | |
| expression.Number | 1 | 1 | 6 | |
| expression.Poly | 3.08 | 5 | 40 | |
| expression.Power | 1 | 1 | 4 | |
| expression.RecurseFunc | 2 | 4 | 10 | |
| expression.Selector | 1.25 | 2 | 5 | |
| expression.Term | 1.14 | 2 | 8 | |
| expression.Var | 1.5 | 3 | 6 | |
| parse.Lexer | 2.75 | 6 | 22 | |
| parse.Parser | 2.4 | 5 | 12 | |
| visitor.Dealer | 4.24 | 10 | 72 | |
| visitor.Displayer | 4 | 9 | 28 | |
| Package | v(G)avg | v(G)tot | ||
| 1 | 1 | |||
| expression | 1.84 | 149 | ||
| parse | 3 | 39 | ||
| visitor | 4.62 | 111 | ||
| Module | v(G)avg | v(G)tot | ||
| oo_homework_2026_24231209_hw3 | 2.52 | 300 | ||
| Project | v(G)avg | v(G)tot | ||
| project | 2.52 | 300 |
层次设计问题:整体看来,代码的层次还是比较清晰的,基本就是按照预处理->解析->组装计算的流程进行。但是在某些类的局部设计可以看出来打破了这个层次。
比如对于Exp类,内部一个属性为inPoly,就是exp内部的表达式,那么为了得到这个表达式,就需要在内部进行一遍这样的流程,所以在局部其实就已经有点打乱了层次的设计。包括在Dealer中直接替换选择表达式,也是类似的操作。这样虽然可以简化后续的很多计算,但是这样会导致很深的递归,所以在处理
1
f(x)=exp(exp(exp(exp(exp(exp(exp(exp(x))))))))+x
0
f(f(f(f(x))))
这样的嵌套的时候时间就爆了
预处理:可以说我Dealer中的预处理方式简直烂爆了。我一开始想的是写一个能够处理各种人能理解的输入,不单单只能处理指导书给出的合法输入。所以,我用了4个方法来处理表达式,结果只能处理无限连续加减号的额外情况,反而还引入了不少错误。
复杂度分析:总体看来复杂度似乎问题不是很大,中间某些方法和类由于分支特判比较多,可能圈复杂度v(G)比较高,部分方法复用情况比较多,基本复杂度和耦合复杂度比较高
总体来说,存在的大部分问题是小问题,可以在局部可以解决。但是复合层数过高导致的时间爆炸对我的设计来说是致命的,不管能修多少小bug,这里有问题只能重写了。唉,还是贪图方便把自己的架构搞得不伦不类的。
第一次作业,主要难点在于怎么设计主要层次。我第一次作业的层次架构感觉还是可以的,处理->解析->组装计算的设计还是很清晰的。
这一部分主要完成了Factor,Expr,Power,Lexer,Parser,Dealer,Visitor,Displayer,Poly的设计,基本架构实现。
第二次迭代,新增指数函数,自定义函数以及选择表达式。
新增Exp,Selector,Func,Key类。
Key类,作为Poly的新的键。但是由于自定义类要实现排序需要重写equal()和hashCode()方法,捣鼓半天都不对,所以放弃排序了,换成HashMap来实现了。Selector和Func类不论以何种形式,都需要从表达式中被替换掉。我想到的最好的办法就是直接在一开始处理的时候直接替换掉。对于函数,只是单纯的字符串替换;但是对于选择式,还需要进行计算,这就要求同样走一遍完整的过程得到结果。当然了,这是可以实现的,而且还挺方便。Exp我将其视为一个因子,内部有一个string的属性,接收内部的字符串形式表达式,然后在类内进行表达式展开于计算,从而可以得到一个inPoly的内部多项式,后续关于exp的计算也都可以直接利用Poly内已经写好的计算方法实现。从这里开始,我的层次化设计开始出现问题了,在内部层次反复调用最顶层的操作,同时基本都是递归调用,不方便调试。
第三次迭代,新增y变量和递推函数
新增Deriver,RecurseFunc类,分别用于处理求导因子和计算递推函数
Poly中新增三个方法derivate,deX,deY。RecurseFunc是Func的子类,具体的替换方式也一样,都是在Dealer中进行替换。不过由于递推函数需要递归才能得到正常表达式,所以该类内部通过一个方法递归调用Dealer实现对函数的递归解析。y变量,所以Var在返回的时候需要进行特判。同时Key中的指数也需要加上y的指数,所以修改为exponentX和exponentY。总体来说,如果前面的架构好的话,第三次迭代其实不算难。我在第二次作业的基础上,只花了1个小时左右的时间就完成了。
第一次迭代
第一次迭代主要是Dealer对表达式的预处理出了一些问题
第二次迭代
主要存在三个bug:
Dealer对表达式的处理出了问题Dealer中函数替换和选择式计算换一个顺序就行。第三次迭代
主要存在两个bug
Poly,但是这就会导致空指针错误第二个bug,在现在代码的基础上基本没法修。要修的话必须把修改Exp的inPoly属性,但是我后续与exp相关的所有计算和多项式的构建都基于此,这个东西一删,和重写基本没有区别。
目前的重构打算是把Dealer里进行函数替换和选择式替换的部分全部删掉,将函数与选择式视为因子,在parser里一起解析。exp也不进行内部解析了,把本来输入为String的构造函数改为输入Expr,最后都统一在Display中进行组装计算
我在输出的优化上并没有思考很多。
第一次作业,基本没有优化,其实也不需要,最短的输出就是确保第一个项的系数是正的
第二次作业,我完全没有考虑优化,exp的指数直接全部乘进去了
第三次作业,我只做了一点优化,就是对于把系数相同的提取系数,然后提出来作为指数,与常规的输出进行长度判断后输出。
在我的作业过程中,大模型只起到辅助作用。每一次作业,代码架构基本都是由我自己构思的,但是在一些具体的实现上,我可能会向AI寻求一些建议。比如,使用访问者模式进行最后的组装计算就是AI给的建议。包括碰到的一些问题,比如重写hashmap的equals方法,这些自己没法解决,就向AI寻求帮助。
我可以说自己代码的AI率不会超过5%。其实我也用AI生成了很多代码,但是不用AI的代码主要是因为感觉自己脑回路和AI对不上,它给10条建议,采用1条已经算是很有用了。
评测的时候使用AI就比较多了。除了第一次作业的评测机是自己写的外,后面两次都是用的AI生成的评测机,还是很好用的。
同房的同学代码看得很少,就算看了,其实我也不太能分辨出来是不是AI写的。我对AI的直觉还是挺差的
我感觉最大的体会还是在于AI的使用吧。
其实这3次作业的成绩还是挺差的,每一次都在c房,但是我又能看到好多同学几乎完全依靠AI,可以进b甚至a房。而且我做作业的效率很低,第一次作业写了几乎3个下午夹晚上,但是有的同学半天就写完了。从这样的对比中可以看出,利用好AI,对写代码真的是有很大的提升。
另外一个就是不要贪图方便而放弃规范性。如果当时没有为了贪图最后计算的简便,而是老老实实把函数,选择式和exp写成规范的因子,也不会出现这样致命的bug了。能不能在debug截至之前重写完就听天由命了。