首页 > 其他分享 >CS61B不相交集笔记

CS61B不相交集笔记

时间:2024-11-24 16:05:49浏览次数:6  
标签:int CS61B 相交 我们 public find 笔记 ds connect

CS61B不相交集笔记


笔记的来源:CS 61B-2024 春季的课程
课程主要内容:数据结构与算法分析
课程运用语言:Java

你可以在我的笔记网站里获得更多有用的资源。

这个课有6 个 Homework,10 个 Lab,9 个 Project。其中第一个 project 是一个完整的 2024 游戏的实现,很有意思。此文章对应的是课程 14 节的内容。主要讲述了一个不相交集的问题

不相交集问题

在这里插入图片描述

我们可以用下面的代码描述上图元素的互相关系

ds = DisjointSets(7)
ds.connect(0, 1)
ds.connect(1, 2)
ds.connect(0, 4)
ds.connect(3, 5)
ds.isConnected(2, 4): true
ds.isConnected(3, 0): false

而不相交集的问题就是实现ds的方法,我们要实现的是:

public class DisjointSets {
    void connect(int a, int b) {}
    boolean isConnected(int a, int b) {}
}

实现方法

集合列表

一开始我们有[{1},{2},{3},{4},{5},{6}]
对于连接操作,我们可以将ab所在的集合合并,即[{1,2,3,4,5,6}]

void connect(int a, int b) {
    int setA = find(a);
    int setB = find(b);
    if (setA!= setB) {
        sets[setA].addAll(sets[setB]);
        sets.remove(setB);
    }
}

最后我们得到的算法性能为:

方法初始化连接查询
集合列表 Θ ( N ) \Theta (N) Θ(N) O ( N ) O(N) O(N) O ( N ) O(N) O(N)

对于这个结果我们并不满意

快速查找

我们将给每一个元素分配一个标识符,这个标识符表示它所属的集合。
在这里插入图片描述

如果合并两个集合,就变成这样:
在这里插入图片描述

代码实现则是这样的:

public boolean isConnected(int p, int q) {
        return id[p] == id[q];
	}

public void connect(int p, int q) {
    int pid = id[p];
    int qid = id[q];
    for (int i = 0; i < id.length; i++) {
        if (id[i] == pid) {
            id[i] = qid;
        }
    }
}

这个算法的性能如下:

方法初始化连接查询
集合列表 Θ ( N ) \Theta (N) Θ(N) O ( N ) O(N) O(N) O ( N ) O(N) O(N)
快速查找 O ( N ) O(N) O(N) Θ ( N ) \Theta (N) Θ(N) O ( 1 ) O(1) O(1)

快速合并

我们已经通过给元素加标识的方法简化了查询操作的算法,接下来我们要利用树的方法来简化连接操作的算法。

在这里插入图片描述

如上图的这个结构,我们可以大概了解这个结构的实现。每当我们将两个元素连接的时候,我们将两个元素的根节点互相连接,就可以实现两个集合的合并。上述情况我们可以得到下表:

element0123456
parent-101-103-1

其中,作为根节点的元素的父节点为-1。接下来我们用代码实现:

public class QuickUnionDS implements DisjointSets {
	private int[] parent;

	public QuickUnionDS(int N) {
        parent = new int[N];
        for (int i = 0; i < N; i++){  parent[i] = -1; }
    }

  	private int find(int p) {
        int r = p;
        while (parent[r] >= 0){ r = parent[r]; }
       	return r;
    }
    public boolean isConnected(int p, int q) {
	    return find(p) == find(q);
    }

    public void connect(int p, int q) {
        int i = find(p);
        int j = find(q);
        parent[i] = j;
    }

...
}

权重

在上面的方法中,有一个问题在于我们直接使用了parent[i] = j;,并没有仔细考虑是将谁做为父节点。这里主要考虑的问题在于,如果一个一个树的层数太多的话,再加到另外一个树的下面,会导致层数变得更多。而层数的增加会导致查找操作的复杂度增加。所以我们在合并的时候需要考虑权重的问题。

在这里插入图片描述

我们采用第二个做法:即将总节点数小的数,加到总节点数大的数的下面。

接下来我们思考一个有意思的问题,即树的高度的最小值是多少?进一步阐述这个问题,即为了使 tree 的高度加一,并且我们利用的方法要是权重快速连接,我们最少需要多少个元素?

我们从一个简单的情况开始看起:
在这里插入图片描述

我们有一个高度为 1 的树(高度不包含父节点),其中包含 2 个元素(这是建立高度为 1 的树的最小元素数)。现在我们要通过连接另外一个树使得生成的树的总高度加一,我们的方法是再加一个高度为宜的树进去,并且该树的大小要小于等于 2(权重条件)。那么答案显而易见了,我们只能加一个和一样的树进去,构造了高度为 2 的树。现在得到的树总元素个数为 4.

在这里插入图片描述

接下来我们可以用递推,或者叫数学归纳法的思想,去解决这个问题了。

我们如果想加一个高度为 k 的树到一个高度为 k 且元素个数控制在最小的树中,我们只能加这个树本身(形状上相同),所以我们可以得到这个问题的答案了。

这样的一个树的高度为 l o g 2 N log_2N log2​N

而这个算法的复杂度就是: O ( l o g 2 N ) O(log_2N) O(log2​N)

权重连接的进阶

现在思考一个问题,**我们是希望树更高还是更矮?**当然是需要树更矮,因为树的高度越低,查找操作的复杂度越低。所以当我们在连接单个元素的时候,我们可以选择将其加入到树的父节点,这样可以使得树的高度更低。就像这样:

在这里插入图片描述

标签:int,CS61B,相交,我们,public,find,笔记,ds,connect
From: https://blog.csdn.net/qq_55297504/article/details/143997853

相关文章

  • Java学习笔记--对象数组,方法参数,命令行参数,快速生成方法
    目录一,对象数组Personp=newPerson();二,方法参数1.基本数据类型做方法参数传递2.引用数据类型做方法参数传递三,命令行参数四,快速生成方法1.快速生成方法2.快速将一段代码抽取到一个方法中 一,对象数组Person[]arr=newPerson[3];Personp=newPerson();......
  • 【跟着阿舜学音乐-笔记】几个实用的和弦公式
    Ⅱ->Ⅴ->Ⅰ连接以目标和弦为主和弦,寻找其对应的Ⅱ级小三和弦与Ⅴ级七和弦构成的Ⅱ->Ⅴ->Ⅰ和弦连接(即Dm-G7-C)。其中,Ⅱ级和弦是下属功能最强的下属和弦,具有最强的倾向属音的属性。而G7和弦是一个调内唯一一个属七和弦(大小七和弦),是一个调的标志,可以根据该和弦找到他属于的调式。......
  • 图论最短路算法笔记
    1图的基本操作1.1图的存储图存储有两种方法:邻接表和邻接矩阵。邻接表:g[N][N]={};...memset(g,0x3f,sizeofg);g[u][v]=w;邻接矩阵:inthead[N]={};memset(head,0x3f,sizeofhead);structedge{intpre,to,val;}EDGE[N];inlinevoidaddedge(......
  • 大模型学习笔记:attention 机制
    UnderstandingQuery,Key,ValueinTransformersandLLMsThisself-attentionprocessisatthecoreofwhatmakestransformerssopowerful.Theyalloweveryword(ortoken)todynamicallyadjustitsimportancebasedonthesurroundingcontext,leadingt......
  • 【学习笔记2】人类视觉、听觉与嗅觉神经系统, The nervous system in vision, hearing,
    人类视觉、听觉与嗅觉神经系统 人类有5种重要的感官系统:视觉、听觉、嗅觉、味觉、触觉Therearefiveimportantsensorysystemsinhumans:vision,hearing,smell,taste,andtouch.【1】(本文介绍前三种)  人类视觉神经系统:人眼视觉系统由三大部分链接而成:视......
  • 机器学习实战笔记34-38:gridsearchcv的进阶使用,无监督学习:kmeans、DBSCAN
    主要讲了gridsearchcv的几种变形使用方式一:全部参数搜索方法是构造机器学习流之后,构造参数空间二:优化评估指标的选择作为网格搜索中输出评估指标的参数,roc_auc参数只能指代metrics_roc_auc_score函数的二分类功能,如果需要多分类,则需要将scoring修改为roc_auc_ovr等参数三......
  • Spring学习笔记_41——@RequestBody
    Spring学习笔记_38——@RequestParamSpring学习笔记_39——@PathVariableSpring学习笔记_40——@RequestHeader@RequestBody1.介绍@RequestBody是Spring框架中用于处理HTTP请求的一个非常关键的注解。它主要用于将客户端发送的HTTP请求体中的JSON、XML或其他......
  • 学习笔记(四十三):@BuilderParam装饰器初始化组件的三种方式
    一、参数初始化组件@BuilderParam装饰的方法可以是有参数和无参数的两种形式,需与指向的@Builder方法类型匹配1、定义一个类作为参数//定义一个对象,ui需要的数据exportclassViewEntity{content:string="sssss";}2、定义一个自定义组件import{ViewEntity}from......
  • 笔记 -- 第五章
    第五章语句简单语句表达式语句:一个表达式末尾加上分号,就变成了表达式语句。空语句:只有一个单独的分号。复合语句(块):用花括号{}包裹起来的语句和声明的序列。一个块就是一个作用域。条件语句悬垂else(danglingelse):用来描述在嵌套的ifelse语句中,如果if比else多时如何处......
  • 笔记 -- 第四章
    第四章表达式表达式基础运算对象转换:小整数类型会被提升为较大的整数类型重载运算符:当运算符作用在类类型的运算对象时,用户可以自行定义其含义。左值和右值:C中原意:左值可以在表达式左边,右值不能。C++:当一个对象被用作右值的时候,用的是对象的值(内容);被用做左值时,用的是对......