面向对象程序设计与构造第三单元总结

面向对象程序设计与构造第三单元总结

初次接触规格的感想体会

本次作业是我第一次接触JML规格,初次接触规格带给我的感受和第一次作业初次使用java以及面对电梯第一次感受多线程好太多太多了。理解JML语言的过程并没有带给我什么烦恼,不过接触规格之后确实让我对我的编程学习有了一个新的认识。

第一次看到规格之后我想的是,这个东西有什么用吗?我们明明可以用很简洁的语言描述这些工作,明明不需要这些看起来十分繁琐虚无缥缈的东西,为什么一定要使用规格这样的方式来向我们描述题目呢。等到开始实现作业代码后我发现,规格这个东西是真的好用,完成作业的过程中,无论我有什么疑问,只需要再回去看一眼规格,就能清清楚楚的明白题目的要求,完全不存在什么讲不清楚的特殊情况。通过规格这样的方式来描述要求彻底消除了自然语言的二义性所带来的不确定的烦恼,我们不再需要去苦苦思索或与同学深夜探讨出题人的这句话表达的是什么意思,在规格中,一切都是一目了然。

不过如果让我来自己写规格的话,我还是很拒绝的,需要完完整整考虑到整个操作过程的一切细枝末节真的是一件很折磨的事,不过这似乎是一个优秀程序员的必备素养?

第一次作业

1.思路分析

不得不说,第一次作业真的是非常简单的一次作业,可能是前三个单元所有作业里面最简单的一次,无论代码量还是思维量都很小。第一次去尝试实现规格中提出的要求,带给我的感受就是我需要清清楚楚的理解规格中每个变量所表示的具体含义,规格中变量的存储方式可能与我们自己的实现方式不同,这就需要我们保证阅读规格的过程中把规格中的变量与我们自己打算实现的变量区分开。

作业需要实现的各个方法中最复杂的一个就是isCircle了,我在作业的实现过程中理所当然的想到可以再给每个人增加一个属性,表示所有符合isCircle的人,ar的时候将两个人的“高阶熟人”合并,不过强测之后发现我出现了一个很愚蠢的bug,A与B是熟人,在B与C成为熟人的时候我只让A加到了C的熟人中,却没把C加到A,这导致了A与C的单向相识,就像我认识助教,而助教不认识我一样。这个bug导致我在最后的强侧中只得到了50分。

三次作业中的所有异常处理的实现都是类似的,为每个异常类增加一个static变量对异常触发次数进行计数。

2.性能分析

实现isCircle的函数确实可以在ar的时候进行预处理,但是处理的方式不应该是我使用的给每个人增加一个高阶熟人属性,ar的过程进行合并,而是应该在network中构建关系图,具体实现我会在后面的作业中说明。

第二次作业

1.思路分析

这次作业新增了group和message类,这次作业中没有很复杂的方法出现,send_message中有一些需要注意到的细枝末节,仔细阅读规格就可以发现。不过由于上一次作业中,我isCircle的实现非常愚蠢,当时虽然没有超时,不过我还是认识到了自己的错误,并在第二次作业重写了这个的实现。我使用的存储方式是在network中构建blocks属性,blocks是由很多block组成的,每个block中的任意两个人都是高阶熟人,也就是能找到某种方式使两个人连起来,这样的实现方式也给我查询连通块个数带来了很大的便利。

2.性能分析

这次我使用blocks的存储方式,isCircle的实现变得十分简洁,解决了这一函数可能导致的超时问题。但是万万没想到,在group中query_group_value_sum这样一个不起眼的函数,我使用最简单的遍历来实现,它的复杂度达到了n²。最终在强测中我有一个测试点没通过,但是互测中被疯狂hack。查看CPU用时后我发现,强测中很多测试点的通过都是很极限的,只有一个测试点没通过真的是不幸中的万幸。

第三次作业

1.思路分析

第三次作业新增了几个Message类,我让这几个类继承了MyMessage类,大多数函数的实现都还是比较简洁的。较为复杂的一个函数是sendmessage,现在的sendmessage需要对新的message类进行一些特殊处理,需要注意到JML规格中的许多细节。还有del_cold_message中我一开始没有注意到需要删除一些message,这也是不细心导致的问题。另外,最短路径的计算可以说是本次作业带来的一个小挑战,我使用了迪杰斯特拉算法,最终实现了相应的功能。

2.性能分析

在中测中,我发现CPU的时间限制从2秒变成了6秒,以为是课程组大发慈悲,不会再卡我们的时间,然而在互测中,我使用的没有优化过的迪杰斯特拉还是被同组的人疯狂针对,被hack4中3,强测也有一个测试点因为CPU超时没有通过,最终只好乖乖将最短路径的算法改回使用优先队列优化过的迪杰斯特拉。

测试方法与策略

使用JUnit编写测试代码对程序进行测试。JUnit的配置和使用都是非常方便的,但是可能测试强度比较弱,不过可以针对不确定的方法块进行功能测试。由于我比较懒,没有进行过多的测试,最后也是在承受了相应的后果。

容器选择和使用的经验

在原来使用容器的过程中我几乎都是能用TreeMap就无脑使用了TreeMap,后来我听说貌似如果不需要排序HashMapTreeMap是要快的,于是我在后面的作业中将容器都改为了HashMap

Person中的熟人属性可以使用HashMap来存储,键是人,值是两个人的value,不过有一个需要注意的点是,如果我们只用Person类作为HashMap的键,是需要重写Hashcode方法的,我在自己的代码中发现了这个问题,于是改成使用人的编号作为键。本以为能借此在互测中收获一下,后来发现貌似没有人和我一样傻。

MyNetwork中我使用了嵌套的HashMap来存储blocks属性,这方便了isCircle方法的实现,但是这为每个人的查询带来了困难,所以我又单独使用了一个people属性来保存所有的人,使用的也是HashMap存储,键是Person的编号,值是Person。

posted @ 2021-05-30 17:03  tiny_dreamer  阅读(57)  评论(1)    收藏  举报