第一单元总结

一、第一次作业

1.1第一次架构图

第一次的主要架构方面是仿照实验中给出的代码来写的语法树,语法树的相关知识在oo的公众号上已经写得十分清楚,故在此不做赘述,主要写一下自己比较特殊的部分。首先是仿照语法树的递归方法来进行相关问题的求解,这就方便了对于最后的结果的运算。第二个比较创新的点是计算器的类,将计算器单独拿出来,单独进行相关的计算方法的更新,这在以后的代码迭代方面起了十分关键的作用,也是这两个不起眼的小优化让我第三单元在不到一个小时之内就写完主要功能,测试用时也不长。

第一次架构是拿Arraylist数组存储最后答案,这让第二次优化格外地费力,因为第二次的最后结果发生了改变,要改变所有的接口来适应新的架构。

1.2复杂度分析

可以发现Parser与Calcu的复杂度比较高,但是这是比较合理的,计算器中的主要操作循环很多,这是算法本身所导致的。

1.3总结

第一次作业本身是有bug的因为用ArrayList存变量很容易爆栈,如果存在像是第二次那样的数据点很容易就被拿下,但是好在第二次成功修复了这个bug

二、第二次作业

2.1架构图

第二次主要增加了函数与指数,函数方面我的主要求法是字符串替换,这种方法其实也存在一些问题,比如说会将exp中的x替换,以及嵌套函数的某些变量因子的替换存在问题,但是这些错误无伤大雅,最致命的问题如何存储指数的问题。我采用了一个最面向对象的方法————第一次作业中寻找相关的最简表示形式,如 a*x^b*exp(factor)的形式来构造相关的容器,并且重新定义相关的加减乘除,用字符串的方式处理其中的因子,暂时不进行相关运算,但是这会让我的程序陷入无数个先有蛋还是先有鸡的问题,最后在无数次的死循环中我终于明白了我的程序最后递归的终点在哪里,我最后判断的地方应该是最小的因子,比如说变量因子与数,这些的equals方法我可以简化去写,这样就可以让我的程序最后存在递归的终点,让我的程序最后涉险过关。

2.2复杂性分析

这一次的复杂度分析比较不理想,主要的问题是计算器中有太多的循环,但是这种循环也正是我的程序性能比较好的关键,但是这也是没有从面向对象的思维向面向过程思维转变的直接体现。

2.3 反思

第二次的架构变化太大,导致最后出现了各种各样的bug甚至出现了某些只有在特定条件下才会出现的bug,这也是整个对象管理的角度上没有做好导致的,下次在处理这些问题的时候要先想好各种对象之间的关系,做好计划再开始写代码。

三、第三次作业

3.1 架构图

第三次整个的架构相比于第二次没有什么变化,所以不再重复说明,第三次求解导数的时候我将导数里面的表达式因子作为字符串重新进行求解,进行求解后再计算导函数最后计算即可。

3.2复杂度分析

3.3 心得体会

第三次作业比较简单,最重要的思想是像第一问求解表达式那样求解求导因子内部的表达式因子的值,这个方法为我测试与写代码省下了不少的时间。

bug修复

本单元强测bug主要出现在第二次作业,归根到底是因为自己对于各种类的所属关系认识不清,最后在判断exp中是否加括号的判断条件时采用了分析输出因子类型的方法来判断是否增加括号,但是实际上即使是expr类型的因子其结果也可能只有一项,而Func类型也有可能存在很多的项,但是我却并没有对这些情况进行特判,而且我的架构设计上存在一个致命的问题就是如何寻找递归的下界,这并不是一个很显而易见的问题,而是要在判断equals的时候进行特判来终止递归,这也就造成了我一开始对于num类型的equals方法写得不够好,一开始认为只有num类型能与num类型相同,但是实际上一个Func类型也有可能是一个单纯的数字,这就让我的equals方法出现了问题,让我的第二次互测直接寄掉。

在修复bug时我想了很多方法,始终被困在判断类型的思维上,但是其实只需要写一个正则表达式判断是否是某些特定的类型来增加括号即可。

Pattern pattern = Pattern.compile("x|x\\^\\d+|(\\-|\\+)?\\d+|exp\\(\\s*\\)"); // 匹配整数和浮点数
Matcher matcher = pattern.matcher(factor.getUform().toString());

bug检测

在检测别人的bug更多是采用大力出奇迹的方法,直接上数据生成器,但是由于笔者比较懒,所以第二三次都没有自己写数据生成器,而是抱紧室友大腿(@高鹏飞),由于python的sympy库实在是太慢了,导致评测机效率并不高,所以最后还是采用对拍的方式来进行bug检测,这种方法也可以检测出是否会输出异常括号,因为这样的话程序也会抛出异常。

优化方法

跟其他的大佬不同,本若狗没有采取提取公因式的方式,由于第一次的输出形式判断逻辑导致我没有办法很好地判断1*exp(x)的1*是否应该删除,但是简单删除所有1*也是不可取的所以在输出的时候在所有的数字前都增加一个空格,然后增加如下代码即可

        s = s.replaceAll(" 1\\*", " ");
        s = s.replaceAll("-1\\*", "-");
        s = s.replaceAll("\\s*", "");

性能优化方面主要是采用了底层的运算方法,直接操作各种数组来进行运算,而不是分类讨论各种类的运算,这种运算方式也让我的程序可以跑很大的数据量,可以跑(1+x)^3000左右的数据也可以秒出。

心得体会

第一单元的主要难点集中在第二次作业,第二次的作业直接让难度提升了一个档次,真正将以前面向过程的思想到面向对象的处理方法开始变化,但是现在主要的感觉时对于某些idea的方便功能与java方法的某些特性使用方面不是特别熟悉,课程组或许可以提供一些学习的资源,例如toString与hascode等方法的应用如果提前给出解决方法或许可以不用在搜索上花费那么多时间。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值