301
社区成员
发帖
与我相关
我的任务
分享简单地说,第一单元的作业主要是实现表达式的化简,第一次作业要求实现对较为简单的表达式的化简作为迭代基础,第二次作业加入了指数函数、嵌套括号以及自定义函数,第三次作业加入了求导因子
一、基于度量来分析自己的程序结构
度量类的属性个数、方法个数、每个方法规模、每个方法的控制分支数目、类总代码规模
(这里由于对每个类的每个属性都设置了访问方式,有些方法使用次数为0)
这里删除了一些用来初始化的类,保留了必要的类。左边Pre为初始化,包括对输入表达式去函数,去指数,添加0等操作。Derive为辅助初始化。这里参考课程组推荐的递归下降算法,建Token流,Lexer与Parser对表达式解析。Coe为基本项中除去x的指数的其余属性。Operation处理零碎的操作。具体的类的设计思路在下文框架设计体验中。
二、架构设计体验
第一次:仅涉及单层括号与x多项式,此时对基本项设置了系数coe(BigInteger),指数expo两个属性,合并时只需判断指数部分是否相等。为了便于统一,对表达式类,项类,因子类都设置了Hashmap<expo, BigInteger>作为其类的属性。
这里主要用到了课程组推荐的递归下降算法,也就是先建立token流,再有lexer对各个“词”解析,建立lexerlist,再传入paser进行语法解析。而paser首先从表达式expr开始,由+/-分割,递归到项,项又由*分割(三次作业均不涉及除法),递归到因子。而因子分为三类,常数,变量x,以及表达式因子,而表达式因子则与表达式类可以看成一类。这里需要设置一个接口Factor用来统一表达式因子,常量因子与变量x因子。若为表达式,则返回到递归的第一层,直到每一项都是一个变量x或一个常数c为递归终点。
最后一步则是由下向上合并,由因子相乘得到每项的hashmap,由项的相加得到表达式的hashmap,再转换为字符串输出即可。
这里特别一提的是对指数的处理,本人是在预处理的时候即展开指数,本质上是字符串的拼接,这也涉及后面爆栈的问题,非常不提倡。这复杂度类似快速幂与死算的区别。还有是对第一项的处理,在我的方法中,第一项必须是一个因子,而若为括号或-+这种符号,则递归全部乱套,所以在预处理的时候需要特别注意添加0。
第二次:本次作业是最难的部分,涉及了多重括号(第一次作业就处理了多层括号),自定义函数(Functions),以及最头疼的exp指数函数。
对于自定义函数,在预处理时,用lastindexof从后向前找函数名,并进行字符串的替换操作,这里需要注意括号的添加。从后向前找也可以避免函数嵌套的问题。
而对于exp的处理则涉及代码的大改。对于表达式的基本项,设置Hashmap<expo,Coe>作为其属性,而Coe则为一个包含Hashmap<string, BigInteger>属性的自建类。此处的string即为exp内的表达式,BigInteger为每项的系数。由于基本项的改变,对于之前所写的运算法则函数也就需要大改,代码量是比较大的。
第三次:本次作业较为轻松,加入了求导部分,这里仅需对基本项写一个自己的求导规则即可。
新场景:
若有多重导数,则只需对第三子作业加入for循环。
若涉及三角函数,则需要改变基本项,使其加入cos与sin部分,设置其括号内为一个string。总体类似exp的处理方式,但是在化简部分还没有具体优秀的方法。
三、分析自己程序的bug
本单元程序的bug主要集中在对边界的判断上,对字符串中括号的处理较为复杂。而最后一次的bug在于处理当x指数不为0/1时,复制了指数为1的代码部分,但漏修改一处参数,导致强测挂了。
由于本人对exp内的属性设为字符串,而不是一个表达式,所以对化简表达式,也就是性能部分遇到了很大的麻烦。也出现了很多bug。例如,若采取递归方式处理此字符串,则需要一个终止条件,而这个终止条件局限于字符串的判断,很难具体给出所有情况。
四、优化
优化部分:1、判断表达式中是否有正数项,若有则提到第一项。2、若系数或指数为特殊的0/1/-1,则可做相应省略。3、也就是最难的涉及exp的化简,首先是对括号内进行递归判断是否相等,其次是对其每项提公因数,这里仅涉及几个固定的因数,如2~10,再向上则会大大增加时间成本,并对其字符串长度进行判断,取最小值。4、这里也是看到强测有数据点可以拆成两个exp相乘的方式,不愧是你6。
五、心得体会及未来方向
第一单元主要是对表达式的去括号与化简,让我对代码的分层,功能的分类有了更直观的了解。同时,讨论了其他同学的框架思路后,对自建类的属性设置有了更好的想法。
最主要的是克服了对测试代码的恐惧。之前一直害怕很长很长的测试数据,但是越害怕强测挂的概率越高。
面对,一定要多去和同学和舍友交流。大家对作业的思路进行沟通后,其实会从更多角度来看待问题,也更有利于设计出更合理的框架。
本人在构建测试数据方面的能力较为欠缺,还需要多向大佬学习,同时在第二单元自行搭建更完善的评测机。
要平衡优化与正确性,任何的优化都需要基于代码输出结果正确。如果过度追求性能而导致出现了部分比较致命的bug,反而会得不偿失。