BUAA-OO-2022 Unit-3 博客总结
本单元的目标为熟悉JML规格
,任务是构建一个包含人、组、网络、消息的社交网络。在维护过程中,我们需要通过某些算法来进行优化以缩减查询时间。抽象来讲,人可以视为社交网络中的一个节点;一个组可以视为社交网络中的连通图;而整张网络可以视为图;人与人的关系便可以看做带权边,由此,我们将一个具体问题转换成了一个图论问题。
架构分析
图模型构建
第一次作业
涉及的元素为人
、组
、网络
;涉及的操作为添加关系(人与人、人与组),查询联通图数量等。
第二次作业
新增元素消息
;有关消息的操作包含添加
、发送
等;同时考察群组部分属性的查询,涉及了最小生成树。
第三次作业
在消息
元素中引入表情
、提醒
和红包
维护策略
在本单元中,涉及性能优化的主要有三点:在维护联通图数量时采用并查集算法;在最小权值搜索时采用 Dijskra 算法;在针对属性查询的操作中采用以空间换时间的思想,实时维护变量简化查询。
路径压缩的并查集
前文提到,可以将组
视为联通图
,因此我们对于组数
的查询实际就是对联通图数量
的查询。而我们可以将每一个联通图视为一个集合,人
作为结点就是集合中的元素,所以当我们可以为每个人附加一个集合
的标识,在添加人与人的关系时就将这个标识统一成一个,这就是并查集的思想。而笔者在合并时同时采取了按秩合并与路径压缩。
堆优化的Dijskra 算法
在最小生成树中,笔者采取了堆优化的 Dijskra 算法,如果未采用堆优化或者使用 DFS
存在较大超时风险。对于该问题,结点是人,而边的权值便是关系中的Value
。
以空间换时间
在对于属性的查询中,如果每次查询再更新,时间复杂大较大。因此我们可以维护对应该属性的变量,在关系更新的时候实时更新该变量,就可以以O(1)
的时间复杂度进行查询。
数据构造与测试
数据构造
数据构造主要采用随机构造与针对构造的方式。随机构造不言而喻,针对构造主要是依据 UML规格
中的细节以及性能进行。
测试
在本地测试时,笔者主要与伙伴采用多人对拍的形式进行。同时,建议在实现过程中独立思考,以免同时和多个伙伴理解错 JML规格
。
BUG 分析
自测
主要是通过大量随机数据与伙伴对拍,同时共享各自认为 JML规格
中可能出现问题的点并进行测试。
强测
笔者三次强测未出现问题。
互测
笔者在第二次作业自测环节末发现了 qgvs
时间复杂度较高的问题,但出于稳妥起见,为避免引入更多 BUG
而没有对该点进行优化,这导致了三次作业中唯一的 BUG
。
而针对他人的测试主要是随机数据的压力测试,以及对组员上限
、qgvs
和并查集维护
、Dijskra实现
进行测试。
Network 拓展
需求
假设出现了几种不同的Person
-
Advertiser:持续向外发送产品广告
-
Producer:产品生产商,通过Advertiser来销售产品
-
Customer:消费者,会关注广告并选择和自己偏好匹配的产品来购买 -- 所谓购买,就是直接通过Advertiser给相应Producer发一个购买消息
-
Person:吃瓜群众,不发广告,不买东西,不卖东西
/*@ public normal_behavior
@ requires contains(id1) && contains(id2) && getPerson(id1) instanceof Advertiser && getPerson(id2) instanceof Customer
@ ensures (getPerson(id2).getAdvertisement.addAll((Advertiser) getPerson(id1).getAdvertisement))
@ also
@ public exceptional_behavior
@ signals (PersonIdNotFoundException e) !contains(id1);
@ signals (PersonIdNotFoundException e) contains(id1) && !contains(id2);
@ signals (PersonTypeNotCorrectException e) contains(id1) && contains(id2) && !(getPerson(id1) instanceof Advertiser)
@ signals (PersonTypeNotCorrectException e) contains(id1) && contains(id2) && getPerson(id1) instanceof Advertiser && !(getPerson(id2) instanceof Customer);
@*/
public void sendAdvertisement(int id1, int id2) throws PersonIdNotFoundException, PersonTypeNotCorrectException;
/*@ public normal_behavior
@ requires contains(id) && getPerson(id) instanceof Advertiser
@ ensures \result == (\sum int i; 0 <= i && i < people.length; people[i] instanceof Customer &&
@ \sum int j; 0 <= j && j < people[i].getPreference && people[i].getPreference[j].equals(id); 1
@ also
@ public exceptional_behavior
@ signals (PersonIdNotFoundException e) !contains(id);
@ signals (PersonTypeNotCorrectException e) contains(id) && !(getPerson(id) instanceof Advertiser)
@*/
public int querySalesValue(int id) throws PersonIdNotFoundException, PersonTypeNotCorrectException;
/*@ public normal_behavior
@ requires contains(id) && getPerson(id) instanceof Producer
@ ensures \result == (\num_of int i; 0 <= i && i < people.length; people[i] instanceof Advertiser &&
@ (Advertiser) people[i].getProducer.equals((Producer) getPerson(id)));
@ also
@ public exceptional_behavior
@ signals (PersonIdNotFoundException e) !contains(id);
@ signals (PersonTypeNotCorrectException e) contains(id) && !(getPerson(id) instanceof Producer)
@*/
public List<Person> queryMarketChannel(int id) throws PersonIdNotFoundException, PersonTypeNotCorrectException;
心得体会
通过本单元,笔者对 JML
有了较为清晰的认识,但笔者认为本单元不应将同学过多的注意点引导至性能优化。
而关于如果书写 JML