首先说说我对JML的理解,JML是一种规范的描述语言,其用途主要分为两方面,对于开发者来说,JML规范了开发程序的需要,类似于黑盒的思想,对于实现本身不关心,只要满足规定的输入和输出即可,这也让我想到了API,另一方面,对于用户来讲,通过JML会更迅速的了解函数的定义和用途,进而正确使用。本单元的设计策略就是在实现JML描述功能的同时进一步的优化效率。
首先千万不要肉眼debug....
刚开始因为感觉这一单元很简单就选择了肉眼debug的方式,最后就死的很惨。后来尝试使用过junit,可是效果并不是很好,主要体现在为了测试一个单元的功能需要在之前预设好相对多样的条件,也许是我并没有真正会使用junit,不过个人感觉除了测试起来可能更加规范,实际上和不使用junit进行单元测试效果差别不大。比较高效的方法是找人对拍。
然后说说这一单元我犯下的无数bug:
1.JML没有读清,误解了JML描述的意思导致实现错误。
2.实现错误,对于诸如idnotfound的异常,我却试图通过id找到PERSON再找回id这一愚蠢的做法。。。
3.时间问题,其实我考虑到了时间问题,但是却使用了一种在这次作业中很愚蠢的做法,主要是针对寻找连通的角色进行的预处理,我企图每增加一个新的person就更新一遍记录每个person可以联通的Person的表,这确实让调用iscircle的效率变为了O(1),但是我却没有意识到我addperson的效率编成了O(n^2),结果就是第二次作业只有一个点没有tle.
4.爆栈问题,递归一定得改循环
考虑到这次作业的大部分数据都具有一一对应的关系(如id<-->person),因此选择hashmap是一个很好的选择,而并不是无脑的使用体中的arraylist(没错就是我)。
本次作业的性能主要是来自于对于数据增删改查的性能的要求。
对于增加和删除,除了数组,各个容器的性能差别不大,对于查找,hashmap有优势,因此决定了容器的使用。
而另一方面,为了保证性能,我们就需要尽可能的减少遍历。
如对于求和操作等,可以在每一次的元素增加和删减时就进行好操作和记录,使得性能从O(N)变为O(1).
而还有几个值得讨论的函数:
1.querysum,参考大佬的做法后,我了解到连通块数其实可以转化为,每次增加一个独立块就加,每次联通一个独立块就减的方式进行性能优化。
2.求方差,对于公式进行变换,从定义是变为∑x2-2(∑x)^2/n+(∑x/n)^2,进而简化运算
3.堆优化后的迪杰斯特拉算法,性能降为nlogn,但是可以进一步的进行优化,把每次计算完的图保存起来,当下一次需要用到一样的图的时候直接调用即可。
本次作业的整体架构已通过给出代码和JML进行规范,大体框架同学们应该都是一致的,不过每个函数的内部实现可能有所差别。大致都是由一个network对象管理多个group,person,message。这种设计我猜主要是因为message,person,group里相互都有一定的包含,没有个明确的上下层次关系,因此设立一个network类统一进行管理。
1.JML仅是对于函数输入输出的规范,切不可对其无脑实现,不然在性能上会吃很大的亏
2.JML是一种很好的了解和解释函数功能的语言,其描述唯一,在以后的开发中很重要。
3.单元测试vs整体测试,笔者这一单元的单元测试并不成功,归根结底是因为对于某一函数的输入输出没有考虑全,对拍固然香,但是在实际开发过程中,对拍显然是困难不可靠的,因此我们应该学会单元测试。
原文:https://www.cnblogs.com/oo19373699/p/14831100.html