CS61B - Disjoint Sets

Disjoint Sets

OK,在这节中我们要做什么呢?我们希望可以有一种方法可以连接两个元素,并且对于给定的两个元素判断它们是否连接。针对这一问题我们将在这一节中给出几种解决的方式,每种方式都有着不同的时间复杂度。

思路设计:

我们肯定是需要两个方法,第一个方法用于连接给定的两个元素;第二个方法用于检测两个给定的元素是否连接。

interface DisjointSet

public interface DisjointSets {
   
    /** connects two items p and q */
    void connect(int p, int q);

    /** checks to see if two items are connected */
    boolean isConnected(int p, int q);
}

就如上面设计思路中所说的,我们创建了两个方法。connect()用于连接、isConnected()用于检测是否连接。

连接方式

我们如何表示连接呢,方法可能有很多种。CS61B中给出的方法是用集合表示连接,举个例子:
i.e. {0}, {1}, {2}, {3}, {4}, {5}
connect(0, 1) -> {0, 1}, {2}, {3}, {4}, {5}
connect(1, 2) -> {0, 1, 2}, {3}, {4}, {5}
connect(4, 5) -> {0, 1, 2}, {3}, {4, 5}
connect(0, 2) -> {0, 1, 2}, {3}, {4, 5} (这里注意到,如果重复连接已经存储在一个集合中的元素,不发生改变)
isConnected(1, 2) -> true
isConnected(0, 4) -> false
connect(1, 4) -> {0, 1, 2, 4, 5}, {3}
isConnected(0, 4) -> true (这里注意,isConnected的结果是随着程序的进行而动态变化的)

QuickFindDS

那么我们来思考如何用语言来表示连接两个元素,首先给出一种最直白的方式,Quick Find,思路如下:

  1. 我们可以先创建一个列表,变将其初始化,让每一个列表中的元素等于其index:
private int[] id;
public QuickFindDS(int N) {
   
        id = new int[N];
        for(int i=0; i<N; i+=1) {
   
            id[i] = i;
        }
    }

这样我们得到了一个初始化后的链表

0 1 2 3 4 5
0 1 2 3 4 5
  1. 我们找到处于连接状态的元素在链表中的位置(index),并将该位置的值设定为相同值:
    举个例子,在这种给定的状态下{0, 1, 2}, {3}, {4, 5},我们的链表如下:
2 2 2 3 5 5
0 1 2 3 4 5

我们通过这种表示方式来体现链表的连接,当我们再执行指令connect(0, 4)时,链表会变成这样:

5 5 5 3 5 5
0 1 2 3 4 5

所以我们的连接方法如下:

public void connect(int p, int q) {
   
        int pIndex = id[p];
        int qIndex = id[q];
        for(int i=0; i< id.length; i++) {
   
            if(id[i] == pIndex) {
   
                id[i] = qIndex;     //sets all connected items the same value
            }
        }
    }
  1. 最后的一步——检查是否连接就变得尤为简单了,只需要检测两个元素对应(index)
  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值