OO第一单元作业总结

陈一飞-22373462 学生 2024-03-20 22:14:38

量化分析

先来看一下完成之后的总体架构(废话不说先上图)。

  • 第三次作业UML类图

    img

  • 第三次作业复杂度分析

    img


    img


    可以看到我们Lexer和Parser类复杂度较高,因为在Lexer类里面我进行了预处理,在Parser类里面解析因子的时候情况较复杂。Polynomial类复杂度高主要是因为在进行计算的时候判断合并。
  • 第三次作业代码量

    img

    第一次作业

    本次作业需要完成的任务是:读入一个包含加减乘乘方以及括号(最多为一层)的单变量表达式,输出恒等变形展开所有括号后的表达式。

    整体架构

    本次作业是基于递归下降的思想进行处理的。
    我的思路是首先进行预处理,删去空白符、连续的加减号、删除前导0,对表达式做初步的简化。然后进行分析和计算。

    Lexer

    在Lexer类里面,我们要完成的工作是分析初步处理之后的表达式的词法。具体实现方法也就是遍历一遍,得到表达式的基本单元并且保存下来以供后续使用,不多赘述。

    Parser

    Parser这个类主要是解析语法,在这个类里面实现了递归下降的方法。具体实现方法是分为ParserExpr, ParserTerm, ParserFactor三个部分,每个方法中调用下一级的方法。到了ParserFactor这里,因为已经到了最底级,所以就在这里返回,依次得到项和表达式。如此表达式就解析完了。
    我在设计这一块的时候逻辑不是很清楚,写的比较杂乱。比如处理开头的'-',我在ParserTerm和ParserFactor里面均有涉及,并且解析方法基本一模一样;在处理'^'的时候,我是在ParserTerm里面把这个项依次乘了这么多遍(当然有关于0的特判),但是这种方法可能会导致处理嵌套^的时候爆内存。这些设计思路让我在hw2的时候大改特改,实在是非常痛苦。

    计算

    在本次作业中,因为只会涉及到多项式也就是 a*x^b 这种形式,所以我在Factor接口下的各个类里面定义了一个Hashmap<Integer,BigInteger>类型的属性用来转化成这种形式,便于计算。
    在计算的时候,Term类里面实现了因子的乘法,Expr类里面实现了项的加法,当有指数相同的时候系数相加在一起,不相同的话Hashmap就多add一个进去。

    bug分析

    在互测时发现了bug,原因是输出会省略'+'。因为我以为Hashmap遍历的时候会按照指数从0到高这样子遍历,因此导致如果不是常数项开头就会少输出第一个'+'。

    优化

    这一次优化主要是最好开头是个正的项,这样可以减少一个'+'。但是这一点我没做处理。

    第二次作业

    本次作业和第一次相比,多了指数函数和自定义函数,同时支持多层括号嵌套。其中多层括号在第一次作业中实际上已经实现了这一需求,因此这一次作业无需考虑这一部分,重点是指数函数和自定义函数的处理,在这两点上需要大量重构。

    整体架构

    相比第一次,我在Parser类里面对^的处理从ParserTerm移到了方法parserFactor里面,避免内存爆掉的问题。

    自定义函数处理

    新建了两个类Function和FunctionFactor。前者用来记录输入进去的函数表达式,有以下两个属性和两个方法:
    private static HashMap<String,String> funcmap; //存放函数名和表达式  
    private static HashMap<String, ArrayList<String>> paramap; //存放函数和形参
    public void addFunc(String input) //记录输入进去的函数并进行解析得到funcmap和paramap
    public static String callFunc(String name, ArrayList<String> actualpara) //将函数的形参替换为实参得到一个新的 String 表达式
    
    FunctionFactor类作为Factor的一个接口,属性和方法如下:
    private String func; //替换之后的函数表达式
    private Expr expr; //解析后的结果
    public Expr setExpr() //解析新得到的函数表达式
    
    经过这两个类的处理就得到了函数替换之后的表达式。
    在ParserFactor过程中,如果解析到了自定义函数,先解析得到函数的实参,然后通过上面两个类的构造得到一个新的表达式因子返回。

    指数函数处理

    首先建立一个类ExpFactor,expr是"exp()"括号中部分,exp是指数函数整体的次数。
    public ExpFactor(Expr expr,BigInteger exp) {
          this.expr = expr; //exp()括号内部分
          this.exp = exp; //exp整体的次数
    }
    
    在Lexer词法分析中,我把exp()作为一个token去分析。在Parser解析的时候,当ParserFactor解析到了"exp()"时就会调用parseExpFactor这个方法。在这个方法中,首先取出来"exp()"括号内的部分,这一部分是一个新的表达式,我们再对这个表达式进行解析,利用解析之后的结果构造一个新的ExpFactor返回。

    计算

    我采用的通项是 a * x^b * exp()的形式,上一次作业的储存方式明显不适用,因此需要一种新的存储方式。
    具体的做法是新建了Unit类作为基本单元,Polynomial类用来存储。Unit类存放了系数,x的指数以及指数函数,定义了setCoe,setExp,setPoly,toString等方法。
    private BigInteger coe;//系数
    private BigInteger exp;//x指数
    private Polynomial polynomial;//指数函数
    
    Polynomial类存放了构成指数函数的各个Unit基本项,同时实现了addPoly,subPoly,multPoly,toString等方法用于实现计算功能并且最后转化输出。
    private ArrayList<Unit> units;
    

    bug分析

    这次作业新增内容有点多,再加上鼠鼠我写的有点匆忙,我也没仔细考虑,bug很多。
  • 函数替换的时候没有对实参套上一层(),导致无法正确处理自定义函数带有^的情况。
  • 指数用的是Integer类型,出现了爆int的情况。
  • 这次没有对equal和Hashcode方法进行重写,因此在合并的时候可能会出现没有合并的情况,比如exp(1+x)和exp(x+1)无法合并。

    优化

    考虑到exp(a*x^b) = exp(x^b)^a,因此可以把各个项的公因子给提出来,比如exp((10 * x))把10提出来少一层括号。但是这涉及到对公因数的讨论,需要提取的是哪个公因数,这部分讨论相对复杂,我优先选择了正确性,没有考虑这部分的优化。讨论区有奆佬们关于此问题的详细讨论(orz)。

    第三次作业

    这一次作业和前两次作业相比,多了求导因子这一部分,同时也支持了函数的嵌套调用。但是因为自定义函数的嵌套调用在第二次作业中就已经可以满足了,这一次实际上我也就只需要实现求导这一部分就行了,需要重构的地方不多。

    整体架构

    这一次作业中我在Expr,Term,Factor添加了求导的方法,Parser中增加对求导因子的处理,总体架构与第二次并没有相差许多。

    关于求导因子的处理

    受上机实验的启发,我也采用了一样的方法。在Expr,Term和Factor接口下的类中都有derivate方法,Factor类型的求导变成Term类,Term类型的求导变成Expr类,Expr类求导还是Expr。
    需要注意的是:求导的时候次数是不是0。如果是0的话就求导就变成1,否则按照求导法则进行计算。ExprFactor类的求导和ExpFactor都需要对里面的表达式进行求导。

    bug分析

    在互测的时候发现有人出现了自定义函数嵌套中有^的情况出现了bug。同时自己的代码性能比较差,会出现TLE的问题。

    优化

    这一部分的优化和第二次的基本相同,不再赘述。

    心得体会

    总的来说,在写作业时需要先想清楚自己的架构,我已经有很多次面对代码发呆的情况;还要注意方法不要写的太过冗余,有很多地方都是复制粘贴,可以定义一个新的方法来实现这部分的功能,同时太长的方法也很有可能出现bug;考虑自己的代码是否能适应一些边界情况,要尝试着去提高代码的性能;细节要考虑清楚,要通过评测机或者自己构造样例去查看自己细节处理是否充分。
...全文
73 回复 打赏 收藏 转发到动态 举报
写回复
用AI写文章
回复
切换为时间正序
请发表友善的回复…
发表回复

301

社区成员

发帖
与我相关
我的任务
社区描述
2023年北航面向对象设计与构造
学习 高校
社区管理员
  • YannaZhang
  • CajZella
  • C_ecelia
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧