OO_Unit3
第一次作业分析
1.bug分析
这次作业中出现了两个bug,首先是忽略了各种情况下PersonId相同的情况,这一点是在规格中有明确说明的,在测试中也忽略了这种情况导致出现了WRONG ANSWER问题。其次是在图的连通性问题中采用深度优先的遍历方式算法复杂度过高出现了CTLE的情况,修改方式是采用添加并查集类,并维护一个该类的对象。
2.hack策略
第一次作业中以为本单元的难点在于如何正确实现JML规格,但实际上更重要的是性能上的测试点更容易失分,因此只是尝试了几个简单的正确性测试点,所以并没有hack成功。
第二次作业分析
1.bug分析
这次作业中出现了三个bug,首先是在看规格的时候没有注意到平均数的方差是最后除以容器大小的(括号太多眼睛看花了);其次是忽略了Group中的人数要小于1111,当时因为这种情况并没有放在异常处理之中,所以没有太在意,忽略了人数超过1111是atg指令仍然会输出OK但是并没有实际想group中家人;最后依旧是CTLE问题,在运算平均数和方差的时候算法复杂度过高,解决方法是维护两个年龄之和和年龄平方之和的变量,然后采用数学公式根据这两个值计算出平均数和方差。
2.hack策略
第二次测试中会出现的性能问题是出乎我的意料之外的,因为第二次实现的函数甚至没有第一次作业中涉及到的函数复杂,没有想到平均数和方差的计算也可能会导致性能上的失分数。
第三次作业分析
1.bug分析
这次作业中出现了三个bug,首先是忽略了多个Message可能具有相同的EmojiId的情况,使得dce命令在去除message时只清除了第一个具有该EmojiId的message,导致其他命令会出现RUNTIME_ERROR的问题;然后依旧是CTLE,求最短路径的算法复杂度依旧过高,忽略了这种社交网络本身是稀疏图的情况,传统的Dijkstra等方法并不是十分使用,解决方案是采用了堆优化的Dijkstra算法;最后是本次作业中对于第二次作业中的qvs指令优化忽视了,当时集中优化在了平均数和方差的优化方法上,没有注意到qvs的算法复杂度也很高,解决方法同样是添加一个中间变量,在群组中添加Person或者Relationship时进行维护。
2.hack策略
本次作业成功吸取了上次hack他人失败的经验,将测试点集中在算法性能的测试上,成功hack了三人,顺便在构造测试用例的过程中,发现了自己的程序在计算最短路径的方法上出现了一些小问题。
容器的选择和使用
1.容器类的选择
在本次作业中我使用的容器类主要是ArrayList和Map,ArrayList用于对于顺序有要求的顺序存储和类似于数组那样使用;Map主要应用在需要使用键值对一一匹配的场合当中。
2.容器类的使用
ArrayList在Person类中充当数组存储message信息,同时也满足了对message信息的顺序要求;在Network类中充当数组存储Person,Group,Message;在Group类中存储本组的Person。
Map在Person类中存储和其他Person的直接关联的value信息;在Network类中存储EmojiId以及相应的引用次数。
性能分析
本次作业的容易出现的性能问题主要出现在图的遍历上,各种遍历的操作都容易出现复杂度过高的情况,但有些指令的遍历工作是具有一定重复性的,因此可以采用维护中间变量的方法,这样便可以避免进行重复性的遍历。然后是图的连通性问题以及最短路径问题,本次作业中涉及到的图都是稀疏图,边的数量十分接近顶点的个数,因此传统的算法解决起来复杂度往往都很高,因此需要采用一些特殊的算法甚至针对性的算法进行优化,在本次作业中学习到了并查集以及堆优化Dijkstra算法等新知识,开阔了眼界。
架构分析
本次作业的架构设计几乎是完全按照JML要求进行的,并没有进行很多额外的思考,但是这样做的缺点就是虽然正确性能够保证,但是性能方面出现了很大的损失。因此完全仿照JML是无法在这次作业中取得很好的成绩的。本次作业中最大的收获是对图模型的构建和维护有了许许多多新的认识,学习到了很多新鲜的知识,这是在规格化设计之外令人欣慰的收获。这次的图模型我认为主要包括三个部分,顶点信息类(Person),图信息类(Network),群组信息类(Group),关键点在于每个部分要单独维护属于自己的信息,要和其他类信息区分开来,这样才能使得图结构较为清晰,各类之间的关系较为清晰。在图维护上面我意识到了维护一些中间变量对图程序的性能优化具有很大的作用,但维护中间变量时一定要仔细思考那些地方会用到或者更改中间变量的值,这种情况往往是在类和类之间进行信息交互的时候会发生。