BUAA-OO第三单元总结

一、前言

本单元主要通过根据官方包中给出的规格实现一社交模拟系统,以此培养阅读JML并依据规格完成代码书写的能力。

二、实现规格采取的策略

在本单元作业中我采取的策略是首先通读官方包中的JML,对各个函数实现的功能大体有所了解,之后阅读作业说明中的数据限制,判断函数是否可以直接照搬规格,如可行则直接对照规格进行实现,如不可行则对函数的实现进行新的设计,多为采用空间换时间的策略,降低时间复杂度。

三、基于JML规格设计的策略和方法

在本单元进行测试时我主要是根据各个函数的规格进行了覆盖测试,通过构造不同的数据以验证函数执行结果是否符合规格。此方法虽然有些繁琐,但可以保证函数实现的正确性,缺陷在于使用此方法不能够对时间复杂度是否符合要求进行测试。

四、总结分析容器选择和使用的经验

当我们主要用于判断容器中是否存在具有某一特性的对象或者需要将对象按照某一性质进行分类存储时,可以使用HashMap/HashSet进行存储;当需要对容器内对象进行便利存储时,选择ArrayList更加高效。当两者均需频繁使用时,可以维护两个容器或将其封装成一个。

五、本单元容易出现的性能问题

本单元后两次作业中如果没有对某一具体指令条数进行限制,则该指令使用O(n^2)的算法均会超时,从笔者第三次作业强测结果来看,如果实现时常数较大,O(mlogn)算法在第二次作业中也可能超时(笔者并未遇到这种情况,不能判断是否正确),下面我将针对各次作业分析容易出现的性能问题。

第一次作业

第一次作业中容易出现超时的方法为query_block_sum(qbs),由于第一次作业指令条数限制较为严格,因此如果没有实现并查集,在query_circle(qci)中使用时间复杂度为O(n^2)算法,并在qbs中照搬规格,则qbs方法时间复杂度为O(n^4),会超过cpu使用时间限制。在互测环节中我阅读了房间内其他同学代码,发现部分同学实现并查集后其qbs指令时间复杂度仍为O(n^2),这虽然符合第一次作业的要求,但在第二次、第三次作业中便不能满足性能要求。
笔者在避免第一次作业中的性能问题时采取的策略是维护一并查集,在addperson和addrelation时分别对其进行修改,这样虽然addperson、addrelation时间复杂度变为O(n),但qbs、qci的时间复杂度均为O(1)

第二次作业

第二次作业中可能出现性能问题的方法为以下几个:
1、query_group_value_sum,笔者解决的方法为维护一sum变量,在add_to_group、add_relation、delete_from_group时对值进行修改,避免超时。
2、如果实现get_age_mean时的方法为遍历容器并进行计算,即时间复杂度为O(n),在get_age_var时直接复制粘贴了规格,则get_age_var时间复杂度为O(n^2),会造成超时,笔者通过在方法内以临时变量存储get_age_mean返回值的方法避免了性能问题,另外如果维护一age平方和变量可以使时间复杂度降至O(1)

第三次作业

第三次作业中可能出现性能问题的方法为以下几个:
1、send_indirect_message方法中如果直接使用dijkstra或spfa等时间复杂度较高的算法,会造成超时,笔者使用优先队列对dijkstra算法进行优化以避免性能问题。
2、delete_cold_emoji方法中如果遍历删除emojiIdList时嵌套遍历messages容器会导致超时

作业架构

以下是第三次作业UML图
image
以下是第三次作业图模型的构建与维护策略
本次作业图模型的节点为person,即addperson相当于加入一个节点,addrelation相当于加入一条带权边,存储图时我使用了HashMap<Integer,ArrayList<person>> circles这一容器,按极大连通子图的方式存储这一图,在其中Integer为子图的id,ArrayList容器负责存储子图所含节点。当进行addPerson时,向circles中加入一新子图,当addRelation时,若id1、id2对应的节点在两个子图中,则将子图合并。在社交模拟系统中,query_circle为判断两节点是否在同一极大连通子图中,query_block_sum则为查询极大连通子图个数,而send_indirect_message则为在极大连通子图中寻找最短路径,因此按照次结构存储调用时较为方便。

posted @ 2021-05-28 21:40  Gyy+  阅读(49)  评论(0编辑  收藏  举报