本单元都是基于JML给出的具体函数规格进行设计。由于JML已经给出,对每个函数的基本功能实现几乎没有难度、也不需要整体架构设计;实现难度主要体现在
在解决策略上,对于难度中的第1点,需要设计较为全面的测试样例(尤其是在中测过弱的情况下);对于第2点,则需要在编写代码时对自己的实现基于评测数据量限制进行有效的复杂度评估,并结合JProfiler等工具进行实际检测。
JML给出程序测试的全部信息。由于JML的存在,在本单元测试时能够进行分函数、有针对性的测试,即使用JUnit
编写针对重点函数的测试样例。
在本单元我使用或曾尝试使用过的容器及特性如下:
compareTo
方法中规定的)大小排序queryNameRank
方法单设一个使用优先队列的peopleRank
属性,但由于qnr指令使用上限为333,直接遍历不会造成时间上的过大负担,同时单开属性会造成较大空间浪费,故作罢。三次作业中,在实现上我认为比较挑战性的方法/方法组及对应设计思路如下:
isCircle()
UnionFind
类,在Network类初始化时初始化,在方法addPerson()
,addRelation()
中进行维护。addPerson
:平均复杂度为常数级(设为$$k$$)addRelation
:$$O(kr)$$,r为关系数queryGroup
的几个运算方法
ageSum
,年龄平方和ageSqrSum
以及值和valueSum
,并在向group加人、删人以及在Network中添加关系(hw10中测时就忘了,于是强测gg)时及时更新,query时直接调用类属性进行。
sendIndirectMessage()
关于图模型的架构,共分为三级:人Person --> 组Group --> 网络Network,涉及到的核心概念有两类:关系Relation和消息Message。
人Person
级别上Relation的存储和维护
Person类中的acquaintance属性 和 value属性:
private final HashMap<Integer, Person> acquaintance = new HashMap<>(5000); // id - Person
private final HashMap<Integer, Integer> value = new HashMap<>(1000); // id - value
Message的存储和维护
Person类中的messages属性:
private LinkedList<Message> messages = new LinkedList<>();
红包、通知和emoji三种不同Message通过继承Message类进行具体实现。
组Group
级别上关于存储:
其中对组的存储主要在Network中的groups属性
private final HashMap<Integer, Group> groups = new HashMap<>(10); // id - Group
以及Group类自身:
public class MyGroup implements Group {
private int id;
private HashMap<Integer, Person> people;
private int ageSum;
private int ageSqrSum;
private int valueSum;
}
具体方法实现:
组的创建和查找:由于数据量限制,组的创建和查找直接对上述HashMap操作即可,无需过多考虑。
组内部统计方法:在Group类中利用类属性进行维护(具体见本文第四部分的2)。
组内Relation的维护:
组中只使用值和,故对关系的记录只维护一个类属性valueSum
即可。
向组里加人时,利用isLinked
遍历加的人的熟人属性,如果两人认识则修改valueSum
。
Network类中addRelation
时需要判断加关系的两人是否在同一组内,若在则需要更新该组的valueSum
:
public void updateRelation(int addRelationValue);
网络Nerwork
级别上Relation的储存和维护
新建并查集类UnionFind
,并在Network类中实例化为类属性unionFind
:
private final UnionFind unionFind = new UnionFind();
public class UnionFind {
private final HashMap<Integer, Integer> roots; // 记录该节点的根节点信息
private final HashMap<Integer, Integer> numEachChain; // 记录各个节点(key)所对应的分量大小,即每条链的节点数
private int chainNum; // 根结点个数
public void add(int id); // 增加节点
public int find(int id); // 查找某节点的根节点
public void merge(int p,int q); // 合并两个节点
public int getChainNum();
addRelation
时即调用并查集merge方法进行节点合并,在isCircle
查询联通性时调用并查集find方法查看两个节点是否具有相同的根节点。Message的存储和维护:
Network类中messages:
private final HashMap<Integer, Message> messages = new HashMap<>(5000);
在addMessage
中增,在sendMessage
,sendIndirectMessage
中删。
*关于emojiMessage
的热度Heat:
Network类中设置类属性emojiMap
--><int emojiId, int Heat>
对每类emoji的热度进行保存,在storeEmojiMessage
中增,在deleteColdEmoji
中删,在sendMessage
,sendIndirectMessage
中修改。
JML规格化在一个大型代码工程中是必要的,其利用规范语言对代码功能进行了详尽的描述。在JML使用上,我认为有以下三个难点:
原文:https://www.cnblogs.com/aucu1608/p/14836744.html