生成树机制实验(1)并查集1

本文深入探讨了并查集这一数据结构,通过树形结构来实现并查集,用于管理分组。介绍了并查集的基本操作——查询元素所属集合与合并集合,并展示了非树形结构与树形结构的对比。同时,文章讨论了如何通过记录树的高度(rank)和路径压缩来优化并查集,避免树的退化,提高效率。
摘要由CSDN通过智能技术生成

生成树机制实验(1)并查集1

定义

并查集(Union Find)是用于管理分组的数据结构。具备两个操作:(1)查询元素a 和 b 是否为同一组

(2) 将元素 a 和 b 合并为同一组。

并查集不能将在同一组的元素拆分为两组。

结构

利用树来实现并查集

有 n 个结点,我们用 n 个元素来初始化这 n 个节点(1 ~ n)。现在分别用树形结构和非树形结构来表示,以 n = 6 为例
			1					5
		 /   |  \				 |
	    2     3   4                6
非树形结构: (1,2,3,4) (5,6)

使用树形结构来表示,每一个组都对应一棵树,然后将问题转化为树的问题,看两个元素是否为同一组,只需要看两个元素的根是否一致。合并时,只需要将一组的根和另一组的根相连即可。

实现
int node[n];	// 定义结点

// 结点初始化
void Init(int n){
    for(int i = 0; i < n; i++){
        node[i] = i;
        /* 初始时,每个结点的根结点为自己*/
    }
}
// 查找当前元素所在树的根结点
int find(int x){
    if(x == node[x])
        return x;
    return find(node[x]);
}
/*这里定义一组递归,例如上面的例子,我们寻找 4, node[4] == 1 !=4 ,所以需要 return find(node[4]),就是顺着根往上找,return find(1),即为1 */

// 合并元素 x,y 所处的集合
void Unite(int x,int y){
    x = find(x);
    y = find(y);
    if(x == y)
        return ;
    node[x] = y;
    /* node[x]=y, 表明将 x 的根结点赋值为 y*/
}

// 判断x,y属于同一集合
bool same(int x, int y){
    return find(x) == find(y);
}
优化并查集

如果随意合并子树会导致树的退化。在树形结构中,如果发生退化,复杂度将会变高(直接退化为线性结构)等等,解决措施:

  • [高度比较] 对于每一棵树,记录树的高度(rank)。在每次合并操作时,将高度最小的树放在高度高的树下,成为它的子树
  • [路径压缩] 将原先间接与根相连的结点,直接相连(在每次查询时完成这一操作)
1						1
|					/    |    \
2				    2     3    4
|
3
|
4
优化后的算法
int node[n];  // 定义结点
int rank[n];  // 定义高度

// 初始化 n 个结点
void Init(int n){
    for(int i = 0; i < n; i++){
        node[i] = i;
        rank[i] = 0;
    }
}

// 查找当前元素所在树的根结点(等价类的代表元)
int find(int x){
    if(x == node[x])
        return x;
    return node[x] = find(node[x]); 
    /* 这里比 return find(node[x])多做的一步是: 将结点直接连到根结点上
    node[x] = find(node[x])
    假设以1-2-3-4为例子
    1-2-3-4
    1-1-2-3
    所以 find(4) node[4] == 3 !=4  return node[4]= find(node[4])= find(3)
    find(3) node[3]==2 !=3 return node[3] = find(node[3])=find(2)
    find(2) node[2]==1 !=2 return node[2] = find(node[2]) = find(1) = 1
    所以结果为: node[2] = 1,node[3]=1,node[4] = 1
    省去后续的遍历*/
}

// 合并元素 x,y 所处的集合
void Unite(int x,int y){
    // 查找到 x,y 的根结点
    x = find(x);
    y = find(y);
    /*这一系列find操作中,可以理解为把 x 所在的边对应的一连串向上的结点连到根结点,和x   	不同分支的没有合并,因此高度可能不同*/
    if(x == y)
        return;
    /* 判断两棵树的高度,然后决定谁为子树
    三种情况,因为如果 rank[x] > rank[y] 或者 rank[y] > rank[x],
    添加子树的高度为 rank[y] + 1 <= rank[x],
    只有当两者高度相等时,完成 rank[x]++,x 作为根结点的操作*/
    if(rank[x] < rank[y]){
        node[x] = y;
    }
    else{
        node[y] = x;
        if(rank[x] == rank[y]) rank[x]++;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值