标签:设计 一个 行数据 查询 根据 for entryset 干什么 lan
在这一单元中,利用JML来检查自己的代码实现是否有遗漏是一个很好的办法,因为JML就是提供了一个形式化的表述,并且给定了规范,可以说只要实现了JML那么基本的正确性就不会有问题了。
因此在这一单元中我主要测试方法是基于JML来进行数据的测试,根据JML给定的各种情况首先检查自己的静态代码是否实现了,其次再随机构造数据来进行测试。在构造数据这一块,我更喜欢先针对几个相关联的指令来测试,比如将qgs,qgps
等查询组内信息的指令作为一组测试,确定这几个方法的实现没有问题之后,再进行比如关于EmojiMessage
的测试。通过这种测试方式,在出现bug的时候可以更好的找到原因,同时更能捋清不同方法之间的调用关系等。
但是为了防止超时有时候我们并不是完全按照规格去实现方法的,因此需要辅以大量的随机测试来发现bug。
在三次作业中,每个类中的容器我都选择了使用hashmap容器来实现,例如 NetWork 中的 people, groups 等,均是以不同数据的id作为key,而将数据本身作为对应的 value,这样在查找数据的时候只要计算 key 的hashcode,大多数情况下可以直接得到对应的数据,少数情况下要处理冲突的问题,需要遍历一部分的数据,但是相比起使用ArrayList等容器来说,在查找数据的时候的复杂度已经下降了很多。
在三次作业中,对于容器的各种操作都还是比较基础的操作,唯一一个比较复杂的地方就是第三次作业中 deleteCodeEmoji 方法中,遍历删除操作要小心。在这个方法中,我们需要完成遍历的同时删除数据,如果使用普通的 foreach 等循环并删除则会导致出错。因此我才用的方法是迭代器删除。
Iterator<Map.Entry<Integer, Integer>> iterator = emojiHeatList.entrySet().iterator();
while (iterator.hasNext) {
Map.Entry<Integer, Integer> entry = iterator.next;
if (...) {
iterator.remove();
}
}
通过使用迭代器删除保证能够完成遍历删除的操作。
我只在第十次作业的强测中出现了CTLE的问题。
通过查看数据可以看到,是关于qbs的查询太慢导致超时。在第九次作业中,我是使用dfs的方法实现qbs的,在第十次作业中,我改为了bfs,但是还是超时了。因为在第十次作业中我反复使用了缓存的思想来优化查询的速度,因此我的修复策略是,每次查询qbs的时候,如果在调用qbs之前有ap或者ar操作的话,那么就需要重新查询连通块数,并且将查询得到的结果保存下来;如果没有这两个操作,那么就返回上次执行qbs保存下来的值,从而解决了频繁调用bfs导致超时的bug
我出现超时的原因是我自己对于多大的数据跑起来需要多长的时间没有一个很好的评估,也没有使用大量的数据来测试自己的程序,导致了性能的问题。
主要的类是 MyPerson 和 MyNetWork
这两个类中的容器全都选择了Hashmap来实现使得查找对应id的人的时候时间复杂度比较低。
第九次作业的难度不大,大部分方法只要翻译一遍JML就可以实现了。本次作业中比较难的函数是isCircle
方法和qbs
方法,在第九次作业中,这两个函数我是使用的dfs
查询来实现的。isCircle
调用dfs的时候查到id2就立刻返回;而qbs
调用dfs则是遍历完所有的点才返回。
本次作业主要是增加了Group类和Message类,对Message的少量操作,以及对于Group的各种属性的查询方法,比如年龄平均值,年龄方差等方法。
为了防止超时,对于Group的属性查询均使用了缓存的方法。即在每次添加人或者删除人的时候,更新Group类中的年龄和,年龄平方和等数据,使得查询平均值和方差的的方法的时间复杂度降到O(1),同时注意精度的问题。特别地,对于Group内地ValueSum的查询要注意,除了在atg
和dfg
中需要更新数据之外,在添加关系的方法ar
中也需要更新对应组内的缓存值。这一点如果只看JML来写的话会容易遗忘,但是在测试中能够测出来。
本次作业主要考察的是对于Message的各种操作。Message的种类增多了,对于每种消息的处理在各种方法中略有不同,因此需要仔细阅读JML才能够确保每个方法完整实现了。
本次作业的难点主要在于send_indirect_message
,这个方法需要我们实现最短路径的算法。我选择了使用Dijkstra
算法,并且采用了堆优化版本的算法,使得查询的复杂度降到O(nlogn)。另外一个就是容器的循环删除问题,这一点在上文中已经说过了,就不再赘述。
其实这一点,因为JML已经提供了相关的设计,所以整个图就已经构建出来了。节点就是MyPerson类,每个节点中的acquaintance
和value
则对应了与他相连接的节点和边(权重),综上所述对于图的构建就已经完成了。
关于图的维护,会改变图的方法只有ap
和ar
两个方法,只要在ar
的时候完成将对应的人加入到另一个人的acquaintance
中并更新value值即可完成对于图的维护。而对于图的信息的查询,比如isCircle
方法等,都是属于作业中比较难的方法,在上文中也已经进行了分析,故不再赘述。
这个单元的作业真的是简单很多很多。留下了激动的泪水。
这个单元除了学习到了JML之外,其实更让我印象深刻的可能是,在拥有一个良好的架构下可以做出多少迭代开发。这个单元的架构其实是给好了的,我们只需要把方法填进去就好了,但是在写方法的时候我就感到了一个好的架构就是这样可以迭代开发,一步步完善下去的,让我意识到自己其实在架构方面还有很多需要学习的。
标签:设计 一个 行数据 查询 根据 for entryset 干什么 lan
原文地址:https://www.cnblogs.com/kneehurts/p/14827169.html