程序结构分析
1.第一次作业
可以看出第一次作业基本就是面向过程来做的。
只有一个多项式类,类中存了每个单项式的系数和指数。
所有的单项式分离工作全都由多项式类的构造方法完成,导致了构造方法的复杂度非常高。
而changeToString方法由于只有这一个类有处理功能,所以写了所有可能的情况,复杂度也非常惊人。
2.第二次作业
这次作业想努力分出一些层次,于是写了多项式类、单项式类和因子类。
但这次作业在我个人心里是非常失败的,因为写到最后我已经分不清我的结构了,这是一开始没想清楚就贸然动手的结果。
特别是factor本来在我的计划之外,但最后由于我觉得不得不用它才临时加入了它,几个类的add方法也是经历了多次临时添加和修改。
于是这次作业成了我自己都根本不愿意再读一遍的代码,并且debug期间也很痛苦。
由这次作业我明白了,能刚开始想清楚再动手写最好想清楚再写。
toString的复杂度还是很高,可能是因为判断部分写的过多了(我的很多优化工作都在这一步进行判定)。
3.第三次作业
这次作业想的比写的久。
但可以看出在check format的地方复杂度普遍比较高(尤其是有括号匹配的情况下),但是我暂时还没有想出比较好的解决方案。
比较满意的是这次用了接口,虽然不知道用法是否正确,但好歹是作出了尝试。
程序Bug分析
1.第一次作业
公测没有出现问题,互测出现的问题在于一个语法错误。
1 if (coe.get(i).equals(new BigInteger("1"))) { 2 tem = tem + "+x"; 3 } 4 if (coe.get(i).equals(new BigInteger("-1"))) { 5 tem = tem + "-x"; 6 } 7 else { 8 tem = tem + "+" + coe.get(i).toString() + "*x"; 9 }
应该一眼就可以看到错误吧...第二个地方else没加,导致如果满足第一个条件,不光会执行第一个if中的内容并且会执行else中的内容。
这是一个比较低级所以也很严重的错误。
2.第二次作业
公测和互测都没有被找到错误,并且由于第二次的代码结构连作者本人我都理不太清楚了,所以也没有过多进行测试。
3.第三次作业
这次的作业可以说非常让我伤心。
一直觉得自己的代码性能虽然很差(0优化),但是正确性应该问题不大。
也非常顺利地通过了中测,结果强测收获了50分的低分,错了整整八个点,其中七个点是同质问题。
所以说,我们还能小看每个bug吗???
Pattern p = Pattern.compile("^cos ?\((.+)\)" + "( ?\^ ?([+-]?\d+))?$");
1 Pattern check = Pattern.compile("^cos ?\( ?"); 2 Matcher checkm = check.matcher(str1); 3 if (checkm.find()) { 4 int end = checkm.end(); 5 int flag = 1; 6 for (int i = end; i < str1.length(); i++) { 7 if (str1.charAt(i) == '(') { 8 flag++; 9 } else if (str1.charAt(i) == ')') { 10 flag--; 11 if (flag == 0) { 12 end = i; 13 break; 14 } 15 } 16 }
对于直接用正则类似(.*)匹配的错误其实很早就注意到了,但是只修改了plus和mult组合的判断,却忘记了cos和sin的判断。
但在我的判断优先级中,constant>pow>cos=sin>mult>plus。
导致了一旦出现cos(x)*(x)类似于这样的东西,不会先判断成mult然后拆分出因子再存成cos和x,而是直接被判断成cos,cos括号中是x)*(x,递归再判断,错误,输出WF!
这个解决方法其实非常简单,只要我自己再多测一测就好,难道我自己构造不出cos(x)*(x)这种测试点吗?
就是因为对测评机的依赖和自己的懒惰,让自己收获了一个真.低分。
Hack策略
由于菜+懒,没有写自动化测试的东西...所以一直在使用老土的办法测试,开7个IDEA,一个个输入输出。
这种方法想要hack别人的确面临重重困难,尤其是自从第二次作业开始,因为你不可能手动帮别人化简输出,因为程序思路千差万别,输出千差万别,肉眼对比输出非常艰辛。
上次听到讨论课他们的分享之后,深感佩服,希望再以后的测评中自己也可以尝试一下自动化测试的方法。
我个人而言分成三个步骤:
1. 罗列自己认为的易错数据,输入输出。
我自己构建的易错数据普遍都比较短,对于这几次的作业,我觉得如果错了这个点那前三项基本就可以找出这个点。这导致我很少先测复杂数据点,但有些同学可能就是复杂数据会出现TLE或者其他玄学错误。
2. 当罗列殆尽,看我会看他们的代码,当然,基本上只会看判断+提取表达式部分和输出部分(输出也是只有第一二次看了,因为第一二次化简的同学比较多,输出很容易有问题)。
我认为这几次的代码由于种种原因,判断和输出的错误率是最大的,让我一次看七份代码并不现实,想要快速纠错,看这几个部分也比较好。
3. 最后挑一份我认为写的比较好的代码通读一遍,目的之一是肉眼debug,当然更重要的是想学习一下。
Applying Creational Pattern
个人认为工厂模式非常切合第三次作业。并且在学习的过程中,也发现了自己构造方法的使用出现了很不好的情况(我的构造方法经常出现非常长的代码,这样就会导致代码很难看也不好修改)。
在学习的过程中,突然发现虽然当时的我脑子里没有工厂模式和工厂类的概念,但其实在写代码的过程中其实隐隐有点这种意思...但是表达得不是很好。
在我的代码中有一个类叫做CheckAndBuild1,其实就是传入String判断应该建立哪一种类后建立再返回这个类,但由于当时并不知道工厂模式是什么东西,然后就用自己的语言写了出来,不是很规范,但学习了以后,发现其实第三次在原思路上可以简单修改一下就完成比较规范的转换。
非常重要的是我现在CheckAndBuild是一个比较复杂的过程(从复杂度也可以看出),应该把Check和Build功能分开来,毕竟感觉看到的工厂模式的工厂例子判断都还比较简单,我这个判断还有一点复杂。