BUAA-OO第三单元:基于JML规格的程序设计

BUAA-OO第三单元:基于JML规格的程序设计

第三单元为根据JML规格语言进行编程,难度相对前两个单元有所下降,不过JML作为一个陌生的语言,在一开始理解它还是有一定的困难的,需要对照着手册不断查询,并且一些复杂的方法用JML语言描述出来是非常冗长的,作业体验有一丢丢差~

架构设计

hw9

UML图

在这里插入图片描述

代码架构及优化思路

第九次作业要求实现一个MyNetwork类,可以在其中添加人,即MyPerson类,在两个人之间可以添加关系并设置权值,即无向有权图,在课程组给出Runner类中会查询其中的相关数值。同时,我们需要自己实现相关异常的抛出,即UML图右边的Exception并打印相关信息。本次作业难度较小,只需对应课程租给出的规格书写即可,但所有方法全部暴力求解是有TLE风险,下面介绍一些优化思路。

并查集优化算法

MyNetwork类中有isCircle方法,判断两个节点是否相连,我们可以采用bfsdfs遍历,是O(V + E)的复杂度。同时,这里使用并查集算法,可以将查询复杂度降到O(1)。其思路如下:

我们可以将并查集理解为在某些节点中,它们两两之间都有一条路径可以到达彼此,我们便可以从这些节点中选择一个节点作为代表,或者作为祖先节点,如果有新的点加入进来,只需将其祖先节点设为这些节点中的某一个即可,因为递归查找某个节点的祖先节点最终都会得到同一个代表,可见下面的具体实现。因此,在判断两个节点是否连通,只需要查询其祖先节点是否一致即可,在初始时,将每个节点的祖先节点都设为自己。

public class Disjoint {
   
    private HashMap<Integer, Integer> path;
    private HashMap<Integer, Integer> depth;
    ...
    public void addPerson(int id) {
   
        if (!path.containsKey(id)) {
   
            path.put(id, id);
            depth.put(id, 0);
        }
    }

    public int find(int id) {
   
        int res = id;
        while (res != path.get(res)) {
   
            res = path.get(res);
        }
        int now = id;
        while (now != res) {
   
            int temp = path.get(now);
            path.replace(now, res);
            now = temp;
        }
        return res;
    }

    public int merge(int id1, int id2) {
   
        int res1 = find(id1);
        int res2 = find(id2);
        if (res1 == res2) {
   
            return 0;
        }
        path.put(res1, res2);
        return -1;
    }
    ...
}
并查集动态维护

然而,在对关系进行删除时,原来存在的并查集便需要重新构建,可以采用删除后重新对所有店遍历构建并查集的方法,这里采用了Yanna学姐博客的方法:

当在modifyRelation() 中检测到需要删掉某条边的时候,就对这条边的两个端点进行DFS 染色,通过判断染色结果来确定设左边点的 idleftId,右边点的 idrightId

  • 首先,将并查集中的 father[rightId] 设置为 null
  • 接着,DFS 遍历并查集将所有与点 leftId 相连的点的 father[] 标记为 leftId;
  • 然后,检查并查集中的father[rightId] 是否为leftId。如果father[rightId] != leftId,则 blockSum++ ;反之,blockSum 不变。
  • 最后,DFS 遍历并查集将所有与点 rightId 相连的点的 father[] 标记为 rightId

具体实现如下:

private void MaintainDis(int id1, int id2) {
   
        disjoint.set(id2, id2);
        dfs(id1);
        if (disjoint.find(id2) == id1) {
   
            disjoint.set(id2, id1);
     
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ribber160

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值